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
输出结果
3.ProxyFactoryBean源码解析
一.new 对象与通知是如何生效的
`ProxyFactoryBean实现了FactoryBean接口,因此最终放到容器中bean应该是重写getObject方法返回的对象
重写的getObject方法
isSingleton() 默认是true
进 getSingletonInstance() 方法
先看 createAopProxy() 方法
判断后决定是用CGLB生成代理类还是使用JDK动态代理
二 容器中获取目标对象与通知是如何生效的
设置为 ProxyFactoryBean 的两个属性值 其中 interceptorNames 是一个字符串数组
看它的initializeAdvisorChain()方法
遍历所有的拦截器BeanName,调用addGlobalAdvisors 方法
addGlobalAdvisors((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
从bean工厂中取出这个bean
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 获取代理对象
看 AspectJAutoProxyRegistrar 组件注册了什么 点进去
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar
实现了 ImportBeanDefinitionRegistrar 接口 ,看重写的 registerBeanDefinitions 方法
注册了AnnotationAwareAspectJAutoProxyCreator
看下 AnnotationAwareAspectJAutoProxyCreator 是什么
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
发现 AnnotationAwareAspectJAutoProxyCreator 继承了 BeanPostProcessor 后置处理器 那么,也就是说SpringIOC初始化每一个bean后,都会执行这个BeanPostProcessor 的实现类 ,而postProcessAfterInitialization的重写方法 在 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator中
2.AbstractAutoProxyCreator的bean初始化后处理
1.执行bean后置处理器的postProcessAfterInitialization方法
2.过滤无需进行AOP的bean
首先看
Object cacheKey = getCacheKey(bean.getClass(), beanName);
跟进
wrapIfNecessary(bean, beanName, cacheKey)
`Advice Pointcut Advisor AopInfrastructureBean 这四种类型的bean直接返回原对象,不需要进行AOP
` shouldSkip() 方法留给程序员决定那些bean不需要AOP
如下面这个bean 将不会被AOP代理
@Component(value = "com.sgg.proxy.bean.MyBean.ORIGINAL")
public class MyBean {
@MyAop
public void method()
{
System.out.println("方法执行了");
}
}
3.找到所有的advice
1.先找常规的 advice 的 子类
接下来我们看 getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null) 这个方法
跟进来到 org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean
跟进 findEligibleAdvisors(beanClass, beanName) 方法
先看 findCandidateAdvisors() 是怎么拿到所有的advice的
跟进来到 org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans()
跟进
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false)
注意方法的四个参数
拿到所有类型为 Advisor 的beanName 注意只是名字 如果有父容器,也取出父容器中的实现了Advisor 接口的bean的Name
拿到所有的beanName后,遍历,
判断是不是正在创建中,如果正在创建中,跳过 然后调用 this.beanFactory.getBean(name, Advisor.class) 获取(没有就创建bean),放到集合List advisors 中然后返回 至此,拿到了Spring容器中所有的advisor的子类
2.切面类的advisor
回到org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors
通常我们都是使用@Aspect定义一个切面类,这种就需要通过this.aspectJAdvisorsBuilder.buildAspectJAdvisors()去找
this.aspectJAdvisorsBuilder.buildAspectJAdvisors()
从容器中取出所有类型为Object的bean 也就是取出所有的bean
拿到class,判断是否有@Aspect注解
调用 List classAdvisors = this.advisorFactory.getAdvisors(factory) 方法 拿到不同的advisor
首先找到类中所有非定义切入点的方法
看adviceMethodFilter过滤器
如果注解类型是PointCut,返回null
回到getAdvisors方法,拿到所有的非@PonitCut的方法后
调用 getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName) 创建 advisor
至此,所有的advisor查找完毕 进行下一步过滤操作
4.按Class类型和方法名匹配符合条件的advisor
回到 findEligibleAdvisors 方法 看如何筛选的
跟进
是不是实现了 IntroductionAdvisor 接口,然后调用 canApply(candidate, clazz) 判断是否能应用
跟进canApply(candidate, clazz) 方法
如果当前advisor 是属于 IntroductionAdvisor ,按Class过滤
如果当前advisor 是属于 PointcutAdvisor
调用 canApply(pca.getPointcut(), targetClass, hasIntroductions) 方法
与当前正在创建的bean匹配的advisor最终都存到了List eligibleAdvisors 中
查找所有的advisor与过滤筛选完成后,进行代理类的创建
5.创建代理类
回到 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary 方法
拿到所有的advice的流程已经走完,接下来就是创建代理类了,画张图,整理下流程
创建代理类的过程,请阅下篇博文