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,就能够实现自动创建代理对象的一个功能,看一下继承结构:
我们主要看左边,可以发现,其实他就是一个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的文章!