在Spring的NamespaceHandlerSupport类中有一个方法registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser),这个方法的作用是用来注册处理自定义文件中的特定的标签
所有的解析器,因为都是对BeanDefinitionParser接口的统一实现,入口都是从parse函数开始的,所以同理AspectJAutoProxyBeanDefinitionParser(用来解析aspectj-autoproxy标签的)的parse函数如下:
public BeanDefinition parse(Element element, ParserContext parserContext) {
//注册AnnotationAwareAspectJAutoProxyCreator
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
//对注解中子类的处理
extendBeanDefinition(element, parserContext);
return null;
}
AopNamespaceUtils类
public static void registerAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
//注册方法,这里使用的register最终获取到的是BeanDefinitionRegistry
//extractSource方法是用来从配置的解析器提供的候选对象中提取源元数据
BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
//处理proxy-target-class和expose-proxy属性
//proxy-target-class 属性是否创建了基于类的(CGLIB)代理?默认情况下,会创建基于Java接口的标准代
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
AopConfigUtils类
//进行注册
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//方法containsBeanDefinition作用判断出给的bean是否存在,在Spring的中所有的beanDefinition都已经被存储在了一个ConcurrentHashMap中,
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
//如果存在就获取对应的BeanDefinition
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
//判断需要注册的Bean的Class是不是就是刚刚从内存中获取到的BeanDefinition的class,如果不是则需要进行不同的Class的优先级的判断。在BeanDefinition中的className可以使子类的class,不一定是运行时的class
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
//findPriorityForClass方法用来寻找需要代理对象的优先级,对应的优先级已经被初始化在了一个List<Class>里面,通过比较class来获取优先级
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
//获取需要被代理对象的代理优先级
int requiredPriority = findPriorityForClass(cls);
//如果缓存起来的class的优先级小于当前需要被注册的bean 对应的class的优先级,那么就把已经缓存起来的bean的class缓存穿进来的class
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//将最后需要设置的class,这知道BeanDefinition的className中
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
//这个order属性表示的是,当有多个修饰方法需要执行的时候,用这个order来保持顺序
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//注册bean到beanDefinition中,(前面讲过注册之后会保存起来的)
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
对AopNamespaceUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法进行分析
//注册AspectJAnnotationAutoProxyCreator
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
//注册或升级AutoProxyCreator定义beanName为org.springframework.aop.config.internalAutoProxyCreator
BeanDefinition beanDefinition =AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
//对于proxy-target-class以及expose-proxy属性的处理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
//注册组件并通知,便于监听器做进一步处理
//其中beanDefinition的className为AnnotationAwareAspectJAutoProxyCreator
registerComponentIfNecessary(beanDefinition, parserContext);
}
在这个方法中主要完成的3件事情,一行代码就是一个完整的逻辑,可以看到思路很清晰,这里的编码方式大家可以借鉴。
1.注册或升级AnnotationAwareAspectJAutoProxyCreator
对于AOP的实现,基本都是靠AnnotationAwareAspectJAutoProxyCreator完成的,可以根据@Point注解定义的切点来自动代理相匹配的bean。但是为了配置,Spring使用了自定义配置来帮我们注册AnnotationAwareAspectJAutoProxyCreator,其中注册就在registerAspectJAnnotationAutoProxyCreatorIfNecessary中实现的。
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
其中registerOrEscalateApcAsRequired是核心
public static final String AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator";
private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//如果已经存在了自动代理创建其且存在的自动代理创建器与现在的不一致那么需要根据优先级来判断到底需要哪一个
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
//根据Bean的名称来找到当前代理器的优先级
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
//根据传进来的ClassName来找到对应的优先级
int requiredPriority = findPriorityForClass(cls);
//如果当前代理器的优先级小于需要注册的处理器的优先级,就改变bean的className属性
if (currentPriority < requiredPriority) {
//改变bean最重要的就是改变bean所对应的className属性
apcDefinition.setBeanClassName(cls.getName());
}
}
//如果已经存在自动代理创建器并且与将要创建的一致,那么无需再次创建
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
上面的代码实现了自动注册AnnotationAwareAspectJAutoProxyCreator类的功能,同时这里还涉及一个优先级的问题,如果已经存在了自动代理创建器,而且存在的自动代理创建器与现在的不一致,那么需要根据优先级来判断到底使用哪个。
2.处理proxy-target-class和expose-proxy属性
useClassProxyingIfNecessary方法实现了proxy-target-class和expose-proxy属性的处理。
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
if (sourceElement != null) {
//获取配置中的proxy-target-class属性(是否强制使用CGLIB)
boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
//获取配置中的expose-proxy属性的处理
boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
AopConfigUtils中的轻质使用Class代理,强制使用的过程其实就是一个属性的设置的过程
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
proxy-target-class:SpringAop部分使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议使用JDK的动态代理),如果==被代理的目标对象实现了至少一个接口==,则==会使用JDK动态代理==。所有该目标类型实现的接口都将被代理。==若该目标对象没有实现任何接口,则创建一个CGLIB代理==。如果你希望强制使用CGLIB代理,需要考虑一下两个问题。
- 无法通知(advise)Final方法,因为它们不能被复写
- 需要将CGLIB二进制发行包放在classpath下面。
与之相较,JDK本身就提供了动态代理,强制使用CGLIB代理需要将<aop:config>的proxy-target-class属性设置为true:
<aop:config proxy-target-class="true">...</aop:config>
当需要使用CGLIB代理和@AspectJ自动代理支持,可以按照一下方式设置<aop:aspectj-autoproxy>的proxy-target-class属性:
<aop:aspectj-autoproxy proxy-target-class="true">
而实际使用的过程中才会发现细节问题的差别。
- JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间建一个接口的实现类来完成对目标对象的代理
- CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高级的代码生成包,底层是靠ASM(开源的Java字节码编辑类库)。操作字节码实现的,性能比JDk强。
- expose-proxy:有时候目标对象内部的自我调用将无法实现切面中的增强,如下示例:
public interface AService {
void a();
void b();
}
@Service
public class AServiceImpl implements AService{
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void a() {
this.b();
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void b() {
}
}
此处的this指向目标对象,因此调用this.b()将不会执行b事务切面,即不会执行事务增强,因此b方法的事务定义“ @Transactional(propagation = Propagation.REQUIRED)”将不会实施,为了解决这个问题,我们可以这么做:
<aop:aspectj-autoproxy expose-proxy="true"/>
然后将上面代码中的this.b()修改为“((AService)AopContext.currentProxy()).b()”即可。通过以上的修改就可以完成a对b方法的同步增强。
最后注册组建并通知,便于监听器进一步处理。
这个类注册了之后就是对于bean的处理了实例化bean后的处理的扩展