0
点赞
收藏
分享

微信扫一扫

Spring】Spring中AOP解析 中 AOP的具体实现

3.ProxyFactoryBean 代理工厂Bean 生产代理类

首先 在Spring中,如果一个类实现了FactoryBean 接口,最终放到容器中的bean是getObject返回的对象

因此,可以通过ProxyFactoryBean 代理工厂bean,创建一个bean的代理类放到容器中

1.案例演示一 new 对象与通知:

配置类

@Configuration
public class MyProxyFactoryBeanConf {

@Bean
public Object proxyBean()
{
//创建代理工厂bean对象
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
//设置代理类
proxyFactoryBean.setTarget(new CGLB_Target());
//添加通知
proxyFactoryBean.addAdvice(new MyAfterReturnAdvice());

return proxyFactoryBean;
}

}

启动类

public class AppTest {

public static void main(String[] args) {

AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MyProxyFactoryBeanConf.class);
CGLB_Target bean = app.getBean(CGLB_Target.class);
bean.say();
}

}

2.案例演示二 容器中获取目标对象与通知

都已经使用SpringIOC容器了,还new 多过时

@Configuration
public class MyProxyFactoryBeanConf {

//被代理的bean
@Bean(name = "targetBean")
public TargetBean createBean()
{
return new TargetBean();
}

@Bean(name = "myBeforeAdvice")
public MyBeforeAdvice createAdvice()
{
return new MyBeforeAdvice();
}

@Bean(name = "proxyBean")
public Object proxyBean()
{
//创建代理工厂bean对象
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
//设置代理类
proxyFactoryBean.setTargetName("targetBean");
//添加通知
proxyFactoryBean.setInterceptorNames("myBeforeAdvice");

//返回代理对象
return proxyFactoryBean;
}


启动类

public class AppTest {

public static void main(String[] args) {

AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MyProxyFactoryBeanConf.class);
TargetBean bean = app.getBean("proxyBean",TargetBean.class);
bean.say();

}

}

这里注意了,默认容器中有两个类型为TargetBean的bean,一个是普通bean,一个是代理bean

输出结果

image-20220406210232616

3.ProxyFactoryBean源码解析

一.new 对象与通知是如何生效的

`ProxyFactoryBean实现了FactoryBean接口,因此最终放到容器中bean应该是重写getObject方法返回的对象

image-20220406204420315

重写的getObject方法

image-20220406204550924

isSingleton()  默认是true

进 getSingletonInstance() 方法

image-20220406204745300

先看 createAopProxy() 方法

image-20220406204904054

image-20220406204947703

判断后决定是用CGLB生成代理类还是使用JDK动态代理

image-20220406205131012

二 容器中获取目标对象与通知是如何生效的

image-20220406210705320

设置为 ProxyFactoryBean 的两个属性值 其中 interceptorNames 是一个字符串数组

image-20220406210725155

看它的initializeAdvisorChain()方法

image-20220406211545665

遍历所有的拦截器BeanName,调用addGlobalAdvisors 方法

addGlobalAdvisors((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));

从bean工厂中取出这个bean

image-20220406211734610

4.BeanNameAutoProxyCreator 根据beanName自动创建代理类

@Configuration
public class MyBeanNameAutoProxyCreator {

//被代理的bean
@Bean(name = "targetBean")
public TargetBean createBean()
{
return new TargetBean();
}

@Bean(name = "myBeforeAdvice")
public MyBeforeAdvice createAdvice()
{
return new MyBeforeAdvice();
}

@Bean(name = "proxyBean")
public BeanNameAutoProxyCreator beanNameAutoProxyCreator()
{
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
//要代理的beanName 可以匹配
beanNameAutoProxyCreator.setBeanNames("target*");
//拦截器链 注意是有顺序的
beanNameAutoProxyCreator.setInterceptorNames("myBeforeAdvice");
return beanNameAutoProxyCreator;
}
}

启动类

public class AppTest {

public static void main(String[] args) {

AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MyBeanNameAutoProxyCreator.class);
TargetBean bean = app.getBean(TargetBean.class);
bean.say();

}

}

注意使用BeanNameAutoProxyCreator 不会创建两个bean,放到容器中的只有代理类

5.Spring的AOP实现

1.@EnableAspectJAutoProxy 开启切面自动代理功能

如果想使用AOP,我们需要在启动类上添加 @EnableAspectJAutoProxy 注解 所以从这个注解开始动刀

注意三个点

导入了一个 AspectJAutoProxyRegistrar 注册组件

@Import(AspectJAutoProxyRegistrar.class)
boolean proxyTargetClass() default false;   //是否使用CGLB创建代理对象
boolean exposeProxy() default false;  //是否将代理对象放入ThreadLocal ,如果为true,可以通过 AopContext 获取代理对象

image-20220407172625393

看 AspectJAutoProxyRegistrar 组件注册了什么 点进去

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar

实现了 ImportBeanDefinitionRegistrar 接口 ,看重写的 registerBeanDefinitions 方法

image-20220407173555722

注册了AnnotationAwareAspectJAutoProxyCreator

看下 AnnotationAwareAspectJAutoProxyCreator 是什么

org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator

发现 AnnotationAwareAspectJAutoProxyCreator 继承了 BeanPostProcessor 后置处理器 那么,也就是说SpringIOC初始化每一个bean后,都会执行这个BeanPostProcessor 的实现类 ,而postProcessAfterInitialization的重写方法 在 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator中

image-20220407174010313

2.AbstractAutoProxyCreator的bean初始化后处理

1.执行bean后置处理器的postProcessAfterInitialization方法

image-20220407175004088

2.过滤无需进行AOP的bean

首先看

Object cacheKey = getCacheKey(bean.getClass(), beanName);

image-20220407180051597

image-20220407180246001

跟进

wrapIfNecessary(bean, beanName, cacheKey)

image-20220407180541891

`Advice Pointcut Advisor AopInfrastructureBean 这四种类型的bean直接返回原对象,不需要进行AOP

image-20220407180652476

` shouldSkip() 方法留给程序员决定那些bean不需要AOP

image-20220407180931716

image-20220407180939761

如下面这个bean 将不会被AOP代理

@Component(value = "com.sgg.proxy.bean.MyBean.ORIGINAL")
public class MyBean {

@MyAop
public void method()
{
System.out.println("方法执行了");
}

}

3.找到所有的advice

1.先找常规的 advice 的 子类

image-20220407183406217

接下来我们看 getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null) 这个方法

跟进来到 org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean

image-20220407183538809

跟进 findEligibleAdvisors(beanClass, beanName) 方法

image-20220407183728843

先看 findCandidateAdvisors() 是怎么拿到所有的advice的

跟进来到 org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans()

image-20220407183946284

跟进

BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false)

注意方法的四个参数

image-20220407184237301

拿到所有类型为 Advisor 的beanName 注意只是名字 如果有父容器,也取出父容器中的实现了Advisor 接口的bean的Name

image-20220407184314220

拿到所有的beanName后,遍历,

image-20220407184552822

判断是不是正在创建中,如果正在创建中,跳过 然后调用 this.beanFactory.getBean(name, Advisor.class) 获取(没有就创建bean),放到集合List advisors 中然后返回 至此,拿到了Spring容器中所有的advisor的子类

2.切面类的advisor

回到org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors

通常我们都是使用@Aspect定义一个切面类,这种就需要通过this.aspectJAdvisorsBuilder.buildAspectJAdvisors()去找

image-20220407191627391

this.aspectJAdvisorsBuilder.buildAspectJAdvisors()

从容器中取出所有类型为Object的bean 也就是取出所有的bean

image-20220407191758870

拿到class,判断是否有@Aspect注解

image-20220407192059106

image-20220407192141474

调用 List classAdvisors = this.advisorFactory.getAdvisors(factory) 方法 拿到不同的advisor

首先找到类中所有非定义切入点的方法

image-20220407192714738

image-20220407192734857

看adviceMethodFilter过滤器

image-20220407192803150

如果注解类型是PointCut,返回null

回到getAdvisors方法,拿到所有的非@PonitCut的方法后

image-20220407192914987

调用 getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName) 创建 advisor

image-20220407193115624

至此,所有的advisor查找完毕 进行下一步过滤操作

4.按Class类型和方法名匹配符合条件的advisor

回到 findEligibleAdvisors 方法 看如何筛选的image-20220407185050346

跟进 image-20220407185142494

是不是实现了 IntroductionAdvisor 接口,然后调用 canApply(candidate, clazz) 判断是否能应用

image-20220407185527734

跟进canApply(candidate, clazz) 方法

如果当前advisor 是属于 IntroductionAdvisor ,按Class过滤

image-20220407185808726

如果当前advisor 是属于 PointcutAdvisor

调用 canApply(pca.getPointcut(), targetClass, hasIntroductions) 方法

image-20220407190237756

image-20220407190252760

与当前正在创建的bean匹配的advisor最终都存到了List eligibleAdvisors 中

image-20220407193703695

查找所有的advisor与过滤筛选完成后,进行代理类的创建

5.创建代理类

回到 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary 方法

image-20220407194010933

拿到所有的advice的流程已经走完,接下来就是创建代理类了,画张图,整理下流程

创建代理类的过程,请阅下篇博文

举报

相关推荐

0 条评论