秒懂AOP?!怎么可能?!真的秒懂

Java传家宝:微信公众号(Java传家宝)、Java传家宝-B站Java传家宝-知乎Java传家宝-CSND

Spring AOP

​ AOP(Aspect Oriented Programming)面向切面编程,同过将多个类和对象之间的公共行为从核心业务中抽离出来,形成一个个切面。可以降低模块之间的耦合度以及减少代码的重复性。通常可用于日志记录、事务管理、缓存管理、性能监控和异常处理。在Spring中,AOP通过动态代理是实现,默认的,如果实现了接口就采用JDK动态代理实现,反之采用CGLIB动态代理实现。

值得注意的是SpringAOP是基于IOC实现的,它只能够增强被IOC容器管理的Bean。

AOP案例

​ 首先,我们先通过AOP实现一个日志记录的效果。先定义一个接口:

public interface MyService {
    public void getDate();
}

定义一个实现类,记得加组件注解:

@Service
public class MyServiceImpl implements MyService {
    @Override
    public void getDate() {
        System.out.println("数据给你给你...");
    }
}

定义切面类,记得加@Component和@Aspect注解:

@Aspect
@Component
public class AopProxy {

    @Pointcut("execution(* com.xyz.aop.service..*(..))")
    public void pointCut(){};

    @Before("pointCut()")
    public void before(){
        System.out.println("都让让,准备拿数据了...");
    }

    @After("pointCut()")
    public void after(){
        System.out.println("数据拿完了,玩儿去吧...");
    }
}

tips:通常 “.” 代表一个包名,“…” 代表包及其子包,"*"代表任意名称,方法参数任意匹配使用两个点 “…”

定义主类,记得加包扫描@ComponentScan和开启切面的注解@EnableAspectJAutoProxy:

@ComponentScan
@EnableAspectJAutoProxy
public class springApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annoIOC = new AnnotationConfigApplicationContext(springApplication.class);
        MyService myService = annoIOC.getBean(MyService.class);
        myService.getDate();
    }
}

注意:这里只能通过MyService.class拿到代理Bean,通过MyServiceImpl.class是拿不到的。其次,如果你没有实现接口,即没有MyService接口,只有MyServiceImpl类,那么是可以拿到的。

区别:如果实现了接口,Spring默认采用JDK动态代理实现,反之采用CGLIB动态代理实现

AOP实现

​ 这里建议关注一下早期Spring配置方法,可以更好的理解和阅读源码。我说一下大概,没有示例:

  • ProxyFactoryBean:用于产生被代理对象,即被增强后的对象
    • +Advice:相当于我们现在配置的一个个@Before、@After等等的方法,粒度控制在类上
    • +Advisor:相当于我们现在定义的切面类@Aspect。包含一个个Advice,以及匹配的需要代理的对象方法,类似@PointCut。粒度控制在方法上
  • AutoProxyCreator:用于自动产生代理对象,无需自己配置代理对象
    • BeanNameAutoProxyCreator+Advice:需要指定类的名称,根据类的名称匹配
    • DefaultAdvisorAutoProxyCreator+Advisor:自动匹配所有的Bean,在Advisor定义需要增强的方法

推荐阅读:javadoop的SpringAOP系列文章,很详细,这里我仅仅做一些阅读后的总结

@EnableAspectJAutoProxy

​ 这个注解用于开启AOP,实现自动为我们配置的@Aspect类匹配对应得对象,创建对应得代理对象,增强对应的对象方法。这个注解就一个作用,将AspectJAnnotationAutoProxyCreator类型的Bean后置处理器注册到容器当中。在Bean对象初始化后,创建对应的代理对象。

AspectJAnnotationAutoProxyCreator:相当于之前版本的DefaultAdvisorAutoProxyCreator的类似功能,这里是通过注解配置的方式,通过该注入的后置处理器对象自动产生代理对象

看一下这个注解内部:

@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;
    boolean exposeProxy() default false;
}

可以看到,使用了一个@Import注解,传入的对象字节码为AspectJAutoProxyRegistrar,该类实现了ImportBeanDefinitionRegistrar,故会使用registerBeanDefinitions()方法中的BeanDefinitionRegistry对象注入BeanDefinition对象到IOC容器中如下:

//AspectJAutoProxyRegistrar
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
//...
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 看名字,将AspectJAnnotationAutoProxyCreator对象注入到容器中
        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
        //...
    }
}
// registerAspectJAnnotationAutoProxyCreatorIfNecessary最终会走到这里
// AopAopConfigUtils
// cls==>AnnotationAwareAspectJAutoProxyCreator.class
// registry==>BeanDefinitionRegistry
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
			"org.springframework.aop.config.internalAutoProxyCreator";
private static BeanDefinition registerOrEscalateApcAsRequired(
			Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
		//...
   		// 获取AnnotationAwareAspectJAutoProxyCreator的bean定义信息
		RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
		//...
    	// 将其注入到IOC容器中,beanName默认为internalAutoProxyCreator
		registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
		return beanDefinition;
	}

AnnotationAwareAspectJAutoProxyCreator

​ 可以看到,最终我们注入了AnnotationAwareAspectJAutoProxyCreator类型的一个Bean,就能够实现自动创建代理对象的一个功能,看一下继承结构:

AnnotationAwareAspectJAutoProxyCreator

我们主要看左边,可以发现,其实他就是一个BeanPostProcessor,也就是一个Bean的后置处理器。

我的IOC源码分析有说到:BeanPostProcessor的调用时机在Bean实例属性注入后,准备执行init-method方法前后分别调用postProcessBeforeInitialization和postProcessAfterInitialization方法。

在AOP生成代理的过程中,主要在postProcessAfterInitialization方法中,也就是说,Spring AOP 会在 IOC 容器创建 bean 实例的最后对 bean 进行处理。其实就是在这一步进行代理增强。我们翻看源码会发现AnnotationAwareAspectJAutoProxyCreator类中的没有postProcessAfterInitialization方法,其实是继承了AbstractAutoProxyCreator的方法,结合上图继承结构也能发现。当我们实例化Bean,属性注入后,需要进行初始化时,会进入到initializeBean方法中,源码如下:

// AbstractAutowireCapableBeanFactory中
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// ..
    try {
        // 属性注入
        this.populateBean(beanName, mbd, instanceWrapper);
       	// 初始化Bean
        exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    } 
//...
}
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        //...
    	//执行BeanPostProcessor的applyBeanPostProcessorsBeforeInitialization
        wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        // ...
    	// 初始化
        this.invokeInitMethods(beanName, wrappedBean, mbd);
   		// ...
        // 执行BeanPostProcessor的applyBeanPostProcessorsAfterInitialization
        wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName)
        // ...
        return wrappedBean;
    }

主要看一下applyBeanPostProcessorsAfterInitialization方法的逻辑,看下源码:

// AbstractAutoProxyCreator中
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
          // 进入这个方法
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// Create proxy if we have advice. 创建代理,如果有advice的话
		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;
}

可以看到先拿到advice,然后创建代理对象createProxy,看一下源代码:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
      @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    // ...
	// 创建ProxyFactory实例
   ProxyFactory proxyFactory = new ProxyFactory();
    // ...
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    // 设置advisors到创建ProxyFactory实例中
   proxyFactory.addAdvisors(advisors);
	// ...
   return proxyFactory.getProxy(getProxyClassLoader());
}

可以看到,就是先创建一个ProxyFactory代理工厂,然后设置一些属性,包括advisors,然后用这个代理工厂去创建对应的代理对象。我们跟踪源码,会发现,Spring先创建了一个AopProxy实例,然后调用了createAopProxy方法,方法源码如下:

// DefaultAopProxyFactory
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    //1 (optimize==false) || (proxy-target-class=true) || (没有接口)
   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      Class<?> targetClass = config.getTargetClass();
      if (targetClass == null) {
         throw new AopConfigException("TargetSource cannot determine target class: " +
               "Either an interface or a target is required for proxy creation.");
      }
       //1.2 如果要代理的类本身就是接口,也会用 JDK 动态代理
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
       // 1.3 没有接口,使用CGLIB
      return new ObjenesisCglibAopProxy(config);
   }
   else {
       // 2 使用JDK代理
      return new JdkDynamicAopProxy(config);
   }
}

到这就结束了,至于最后JDK动态代理的实现和CGLIB动态代理的实现,就不解析了,可以参考javadoop的文章!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值