在上一篇spring-AOP(一)實現原理咱們瞭解瞭如何使用ProxyFactory來建立AOP代理對象,但其過程須要實現一些接口,而且須要一些比較複雜的配置。所以,在spring2.0以後,提供了一種較爲便利的方式。 使用@Aspect註解聲明一個切面類,以後經過@EnableAspectJAutoProxy註解來註冊代理生成類AnnotationAwareAspectJAutoProxyCreator。下面咱們來看一下其原理java
package com.luhc.springaop.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/** * @author luhuancheng * @date 2018/11/20 */
@Aspect
public class PerformanceTraceAspect {
@Pointcut("execution(* *..*method1()) || execution(* *..*method2())")
public void pointcutName(){}
@Pointcut("@annotation(AnyJoinpointAnnotation)")
public void matchPointcut(){}
@Before("matchPointcut()")
public void before() {
System.out.println("+++++++++@annotation++++++++++");
}
@Around("pointcutName()")
public Object performanceTrace(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
return joinPoint.proceed();
} finally {
System.out.println(String.format("cost time %s", System.currentTimeMillis() - start));
}
}
}
複製代碼
private static void manualWeaver() {
// 手動織入
AspectJProxyFactory weaver = new AspectJProxyFactory();
weaver.setProxyTargetClass(true);
// 聲明目標對象
weaver.setTarget(new Foo());
// 聲明切面
weaver.addAspect(PerformanceTraceAspect.class);
// 獲取代理
Object proxy = weaver.getProxy();
// 執行已經織入切面邏輯的方法
((Foo) proxy).method1(new FlyImpl());
((Foo) proxy).method2();
}
複製代碼
自動織入方式須要AnnotationAwareAspectJAutoProxyCreator類的支持,經過將AnnotationAwareAspectJAutoProxyCreator和須要的Aspect切面、以及目標對象聲明在IOC容器中,在容器啓動期間,AnnotationAwareAspectJAutoProxyCreator將自動爲目標對象生成織入切面邏輯的代理對象spring
package com.luhc.springaop.aspect;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/** * @author luhuancheng * @date 2018/11/21 */
@Configuration
public class AspectConfigure {
/** * 自動織入器 * @return */
@Bean
public AnnotationAwareAspectJAutoProxyCreator proxyCreator() {
AnnotationAwareAspectJAutoProxyCreator proxyCreator = new AnnotationAwareAspectJAutoProxyCreator();
// 默認爲false,若是目標對象未實現接口的話,其代理對象也是經過cglib生成
proxyCreator.setProxyTargetClass(false);
return proxyCreator;
}
/** * 未實現接口的目標對象 * @return */
@Bean
public Foo foo() {
return new Foo();
}
/** * 切面 * @return */
@Bean
public PerformanceTraceAspect performanceTraceAspect() {
return new PerformanceTraceAspect();
}
}
複製代碼
private static void autoWeaver() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AspectConfigure.class);
Foo foo = context.getBean(Foo.class);
// 此時的foo對象,是以及通過AnnotationAwareAspectJAutoProxyCreator處理後的代理對象
foo.method1(new FlyImpl());
foo.method2();
}
複製代碼
Spring AOP支持如下的Pointcut表達式ide
// 任意包下的具備任意參數、任意返回值的任意方法
// @Pointcut("execution(* *..*(..))")
// com.luhc.springaop的任意子包下的任意類,springAOP只支持方法級別的JoinPoint,所以這個表達式將匹配指定類所聲明的全部方法執行
// @Pointcut("within(com.luhc.springaop..*)")
// 匹配代理對象類型爲Foo的全部方法級的JoinPoint
// @Pointcut("this(Foo)")
// 匹配目標對象類型爲Fly的全部方法級的JoinPoint
// @Pointcut("target(Fly)")
// 匹配傳入參數類型爲Fly和Foo的全部方法執行的JoinPoint,不關心方法在哪一個類中定義
// @Pointcut("args(Fly,Foo)")
// @within @target的區別在於@within是靜態匹配、@target是在運行時動態匹配
// 匹配全部被註解AnyJoinpointAnnotation標註了的類的全部方法級的JoinPoint
// @Pointcut("@within(AnyJoinpointAnnotation)")
// 匹配全部目標對象唄註解AnyJoinpointAnnotation標註了的類的全部方法級的JoinPoint
// @Pointcut("@target(AnyJoinpointAnnotation)")
// 匹配方法參數類型被註解AnyJoinpointAnnotation標註了的全部方法級的JoinPoint
// @Pointcut("@args(AnyJoinpointAnnotation)")
// 匹配方法被註解AnyJoinpointAnnotation標註了的全部方法級的JoinPoint
// @Pointcut("@annotation(AnyJoinpointAnnotation)")
// 可使用 || 和 && 來表達pointcut之間的邏輯運算
// @Pointcut("execution(* *..*method1()) || execution(* *..*method2())")
複製代碼
AnnotationAwareAspectJAutoProxyCreator經過反射獲取到@Pointcut註解的信息,在內部實例化爲AspectJExpressionPointcut對象。 AspectJExpressionPointcut實現了ClassFilter、MethodMatcher,其內部實現邏輯代理給了PointcutParser,最終生成爲PointcutExpression(PointcutExpressionImpl實現類)實例源碼分析
將Advice方法的第一個參數聲明爲org.aspectj.lang.JoinPoint類型,咱們能夠經過調用org.aspectj.lang.JoinPoint相關方法獲取須要的數據post
@Before("matchPointcut()")
public void before(org.aspectj.lang.JoinPoint joinPoint) {
// 獲取方法名
System.out.println(joinPoint.getSignature().getName());
System.out.println("+++++++++@annotation++++++++++");
}
複製代碼
// 能夠同時使用標識符和JoinPoint,可是JoinPoint必須放在第一個參數位置上
@Before("matchPointcut() && args(name)")
public void before(JoinPoint joinPoint, String name) {
System.out.println("獲取到Joinpoint上的入參:" + name);
System.out.println("獲取到Joinpoint的方法名: " + joinPoint.getSignature().getName());
}
複製代碼
@AfterThrowing(pointcut = "matchPointcut()", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, RuntimeException e) {
System.out.println("方法:" + joinPoint.getSignature().getName() + "發生異常:" + e.getMessage());
}
複製代碼
@AfterReturning(pointcut = "pointcutName()", returning = "result")
public void afterReturning(JoinPoint joinPoint, String result) {
System.out.println("方法:" + joinPoint.getSignature().getName() + "得到返回值:" + result);
}
複製代碼
@After("pointcutName()")
public void after(JoinPoint joinPoint) {
System.out.println("方法:" + joinPoint.getSignature().getName() + ": 執行完畢");
}
複製代碼
@Around與其餘幾個Advice註解不一樣,在@Around方法中,第一個參數必須爲org.aspectj.lang.ProceedingJoinPointui
@Around("pointcutName()")
public Object performanceTrace(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
return joinPoint.proceed();
} finally {
System.out.println(String.format("cost time %s", System.currentTimeMillis() - start));
}
}
複製代碼
// 在目標對象方法中,經過此方法能夠獲取當前目標對象的代理對象
AopContext.currentProxy()
複製代碼
咱們使用註解配置的一個spring aop的demo(新版本的spring中推薦使用註解來配置容器)this
// 假設這是一個業務接口
public interface Fly {
void fly();
}
// 業務接口實現
public class FlyImpl implements Fly {
@Override
public void fly() {
System.out.println("++++++++++++++++ Fly ++++++++++++++++");
}
}
// 聲明一個切面
@Aspect
public class PerformanceTraceAspect {
// 匹配任意返回值、任意包下的、任意參數的fly方法。在這個demo中,將匹配到com.luhc.springaop.aspect.FlyImpl#fly這個方法
@Pointcut("execution(* *..*fly(..))")
public void pointcutName(){}
// 聲明切入的前置邏輯
@Before("pointcutName()")
public void before(JoinPoint joinPoint) {
// 能夠經過JoinPoint獲取到pointcut方法的詳細信息
System.out.println("Before --> 獲取到Joinpoint的方法名: " + joinPoint.getSignature().getName());
}
// 聲明切入的後置邏輯
@After("pointcutName()")
public void after(JoinPoint joinPoint) {
// 能夠經過JoinPoint獲取到pointcut方法的詳細信息
System.out.println("After --> 獲取到Joinpoint的方法名: " + joinPoint.getSignature().getName());
}
// 聲明切入的環繞邏輯(即在方法執行先後切入邏輯)
@Around("pointcutName()")
public Object performanceTrace(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
// 調用執行鏈
return joinPoint.proceed();
} finally {
System.out.println(String.format("cost time %s", System.currentTimeMillis() - start));
}
}
}
// 配置類
@Configuration
// 啓用AOP
@EnableAspectJAutoProxy
public class AspectConfigure {
/** * 實現接口的目標對象 * @return */
@Bean
public Fly fly() {
return new FlyImpl();
}
/** * 切面 * @return */
@Bean
public PerformanceTraceAspect performanceTraceAspect() {
return new PerformanceTraceAspect();
}
}
// 運行應用
public class AspectJDemo {
// 使用配置類,初始化容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AspectConfigure.class);
// 從容器中獲取業務接口(此時已是被處理過的代理對象,即已經切入了切面邏輯)
Fly fly = context.getBean(Fly.class);
fly.fly();
}
複製代碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
// 是否使用cglib來生成代理
boolean proxyTargetClass() default false;
// 是否將代理綁定到ThreadLocal,後續在目標類中可使用AopContext.currentProxy()來獲取代理對象
boolean exposeProxy() default false;
}
複製代碼
重點在其元註解@Import上(有機會再分析一下關於spring的@Import註解導入機制),其導入了配置類AspectJAutoProxyRegistrarlua
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/** * Register, escalate, and configure the AspectJ auto proxy creator based on the value * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing * {@code @Configuration} class. */
@Override
public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 重點!!此處向容器注入了AnnotationAwareAspectJAutoProxyCreator類
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
複製代碼
public abstract class AopConfigUtils {
/** * Stores the auto proxy creator classes in escalation order. */
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<Class<?>>();
/** * Setup the escalation list. * 在spring中,默認存在三個代理生成類。優先級別從上到下排序,越日後優先級越高 */
static {
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); // 最高優先級
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
// 若是容器當前已經註冊了代理生成器類,則比較其與AnnotationAwareAspectJAutoProxyCreator的優先級。取優先級最高的那個做爲代理生成器註冊在容器中。
// 顯然AnnotationAwareAspectJAutoProxyCreator被註冊到容器中
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
}
複製代碼
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
if (beanName != null) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
return null;
}
// 生成代理對象
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 跳過基礎設施類
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 跳過基礎設施類
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 獲取切面Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
protected Object createProxy( Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 解析目標對象接口
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 生成Advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 生成代理
return proxyFactory.getProxy(getProxyClassLoader());
}
}
複製代碼