通过上一篇文章Spring Bean的创建过程及相关扩展点的介绍,我们知道getBean()创建Bean实例的过程,有以下几个扩展点:
- Bean实例创建之前实现InstantiationAwareBeanPostProcessor接口
- Bean实例创建成功后,未设置属性时,立马创建一个工厂方法。可通过实现SmartInstantiationAwareBeanPostProcessor接口对Bean增强
- Bean初始化的生命周期中,实现BeanPostProcessor接口对Bean增强
SpringBoot如何实现Aop:
1.先从spring-boot-autoconfigure包下面的/META-INF/spring.factories开始,可以发现AopAutoConfiguration这个类,说明在引入spring-boot-autoconfigure这个jar包后,就会自动加载AopAutoConfiguration。
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class ClassProxyingConfiguration {
ClassProxyingConfiguration(BeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
}
}
}
主要是看EnableAspectJAutoProxy这个注解,无论如何,这个注解都会生效
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass() default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since 4.3.1
*/
boolean exposeProxy() default false;
}
进一步看一下
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 != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
AnnotationAwareAspectJAutoProxyCreator类的UML图
image-20210701142934998.png
可以看到,AnnotationAwareAspectJAutoProxyCreator这个类是实现了InstantiationAwareBeanPostProcessor、SamrtInstantiationAwareBeanPostProcessor、BeanPostProcessor接口的,那么说明这个类是可以在Bean实例创建过程中,对Bean创建过程进行拦截和增强的。
同样的,AspectJAwareAdvisorAutoProxyCreator这个类其实就是基于XML配置来对Bean进行拦截和增强的。
1.在Bean实例化之前:
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !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;
}
}
// 这是重点----这是重点-----这是重点
// 从这里可以看出,这又是一种创建Bean实例的方式
// 通过自定义的TargetSource来创建Bean实例。属于非常规用法。
// 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.
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// 收集所有的Advisor后,通过MethodInterceptor创建代理。具体的实现可以是JDK或者CGLIB
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
在此基础上,我们可以自定义一个BeanPostProcessor,针对AnnotationAwareAspectJAutoProxyCreator进行拦截,在AnnotationAwareAspectJAutoProxyCreator初始化生命周期中,给它创建一个TargetSource对象设置进去,这样就可以促使getCustomTargetSource()方法生效了。
2.另一个就是在Bean实例化后,把Bean对象放进第三级缓存中
// AbstractAutowireCapableBeanFactory类中587行
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// ********这是关键点********这是关键点********这是关键点********这是关键点********
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
// AbstractAutoProxyCreator类中237行,AbstractAutoProxyCreator是SmartInstantiationAwareBeanPostProcessor子类,是实现AOP的入口
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// ********这是关键点********这是关键点********这是关键点********这是关键点********
return wrapIfNecessary(bean, beanName, cacheKey);
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && 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;
}
// 获取所有的Advisor实例,并筛选出匹配的Advisor实例
// 获取Advisor的方式也是通过getBean()的方式,根据指定目标为Advisor.class查找
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 根据筛选出来的Advisor实例,创建代理对象
// 如何创建的代理,其实就是使用了JDK动态代理或者CGLIB动态代理实现
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回增强后的Bean对象
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
3.Bean初始化后
// AbstractAutoProxyCreator类中295行
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// ********这是关键点********同上********同上********这是关键点********
// 和上面的wrapIfNecessary()一样
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
根据AbstractAutoProxyCreator来看,AOP切入的点有三个地方:
1.postProcessBeforeInstantiation():就是在Bean还没有创建出来之前,这个点是留给开发者自己扩展的。针对自定义TargetSource,检查是否有匹配的Advisor,如果有的话,那么就创建对应的代理对象。
2.postProcessAfterInitialization():这个就是Bean已经完成了初始化了,这个时候的Bean已经准备发布了,那么针对这个Bean对象,检查是否有匹配的Advisor,有的话,就创建对应的代理对象。
3.getEarlyBeanReference():这个就是Bean刚刚创建出来,还没有设置属性值,还不能发布,但是为了解决循环依赖的问题,需要先把这个Bean的引用发布出去。那么针对这个Bean就要检查是否有匹配的Advisor,有的话,创建代理对象。
在这三个扩展点,分别会做以下几件事情:
1.findCandidateAdvisors()方法获取所有的Advisor实例,并存放到一个数组里面;原理还是getBean()方式查找Advisor.class所有实例
2.findAdvisorsThatCanApply()方法从数组中筛选出拦截这个Bean的Advisor,有拦截class的,也有method;主要区分出IntroductionAdvisor、PointcutAdvisor;
- 2.1:IntroductionAdvisor只能拦截class,PointcutAdvisor可以拦截method和class。
3.针对筛选出来的Advisor排序
4.根据筛选出来的Advisor对象,通过ProxyFactory.getProxy()创建代理。
另外,再介绍两个手动编程创建代理对象的类:
- AspectJProxyFactory
- 这个类包含两个功能:创建代理的功能;处理Advisor、Advice的功能
- ProxyFactory
- 这个类只能创建代理,Advisor、Advice需要自己手动创建
以上两个类的区别在于,AspectJProxyFactory这个类里面有一个ReflectiveAspectJAdvisorFactory对象属性专门用来处理并生成Advisor、Advice。
共同点就是都能创建代理对象,主要是因为这两个类都继承自ProxyCreatorSupport。
网友评论