关于Spring Aop的实现,由于其是使用自定义标签进行驱动的,因而读者朋友如果对Spring如何实现自定义标签比较熟悉,那么可以继续往下阅读,否则可以阅读完本文后再本人前面的文章Spring自定义标签解析与实现。
首先我们声明了一个切面类如下:
@Aspect
public class DogAspect {
@Around("execution(public void com.business.Dog.*(..))")
public Object aspect(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("before run.");
Object result = joinPoint.proceed();
System.out.println("after run.");
return result;
}
}
该切面类主要用于环绕com.business.Dog类中的public类型的,并且返回值是void的所有方法,下面我们就在com.business包中声明一个Dog类如下:
public class Dog {
public void run() {
System.out.println("Tidy is running.");
}
}
这里切面类和目标类都已经声明完成,但如果不将其加入Spring容器中,其是不会工作的,加入容器的方式非常简单,下面就是一种方式:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="dog" class="com.business.Dog"/>
<bean id="aspect" class="com.business.DogAspect"/>
<aop:aspectj-autoproxy/>
beans>
这里需要说明的是,将DogAspect声明为一个bean并不能使其工作,因为其也仅仅只是一个bean而已,要使其工作还需要使用上面的
public class DogApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Dog dog = context.getBean(Dog.class);
dog.run();
}
}
执行结果如下:
before run.
Tidy is running.
after run.
可以看到,我们在驱动类中获取的是Dog的实例,并且运行其run()方法,但是最终的运行结果中也运行了切面类中的环绕逻辑。
根据前面对Spring自定义标签使用的讲解,我们知道这里
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
这里我们打开AopNamespaceHandler,其实现如下:
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
可以看到,我们需要解析的标签解析器在这个类中进行了注册,即AspectJAutoProxyBeanDefinitionParser,打开这个类其主要实现如下:
class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
// 解析标签的时候将会执行的方法
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 注册一个类型为AnnotationAwareAspectJAutoProxyCreator的bean到Spring容器中
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
// 通过读取配置文件对扩展相关属性
extendBeanDefinition(element, parserContext);
return null;
}
private void extendBeanDefinition(Element element, ParserContext parserContext) {
// 获取前面注册的AnnotationAwareAspectJAutoProxyCreator对应的BeanDefinition
BeanDefinition beanDef =
parserContext.getRegistry().getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
// 解析当前标签的子标签
if (element.hasChildNodes()) {
addIncludePatterns(element, parserContext, beanDef);
}
}
// 解析子标签中的name属性,其可以有多个,这个name属性最终会被添加到
// AnnotationAwareAspectJAutoProxyCreator的includePatterns属性中,
// Spring在判断一个类是否需要进行代理的时候会判断当前bean的名称是否与includePatterns中的
// 正则表达式相匹配,如果不匹配,则不进行代理
private void addIncludePatterns(Element element, ParserContext parserContext, BeanDefinition beanDef) {
ManagedList<TypedStringValue> includePatterns = new ManagedList<>();
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node instanceof Element) {
Element includeElement = (Element) node;
// 解析子标签中的name属性
TypedStringValue valueHolder = new TypedStringValue(includeElement.getAttribute("name"));
valueHolder.setSource(parserContext.extractSource(includeElement));
includePatterns.add(valueHolder);
}
}
// 将解析到的name属性设置到AnnotationAwareAspectJAutoProxyCreator
// 的includePatterns属性中
if (!includePatterns.isEmpty()) {
includePatterns.setSource(parserContext.extractSource(element));
beanDef.getPropertyValues().add("includePatterns", includePatterns);
}
}
}
这里我们继续看AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);方法,该方法的实现如下:
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注册AnnotationAwareAspectJAutoProxyCreator的BeanDefinition
BeanDefinition beanDefinition =
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 解析标签中的proxy-target-class和expose-proxy属性值,
// proxy-target-class主要控制是使用Jdk代理还是Cglib代理实现,expose-proxy用于控制
// 是否将生成的代理类的实例防御AopContext中,并且暴露给相关子类使用
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 将注册的BeanDefinition封装到BeanComponentDefinition中
registerComponentIfNecessary(beanDefinition, parserContext);
}
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry,
@Nullable Element sourceElement) {
if (sourceElement != null) {
// 解析标签中的proxy-target-class属性值
boolean proxyTargetClass =
Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
// 将解析得到的proxy-target-class属性值设置到上面生成的
// AnnotationAwareAspectJAutoProxyCreator的BeanDefinition的proxyTargetClass
// 属性中
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
// 解析标签中的expose-proxy属性值
boolean exposeProxy =
Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
// 将解析得到的expose-proxy属性值设置到
// AnnotationAwareAspectJAutoProxyCreator的exposeProxy属性中
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition,
ParserContext parserContext) {
// 如果生成的AnnotationAwareAspectJAutoProxyCreator的BeanDefinition成功,则将其封装到
// BeanComponentDefinition中,并且将其添加到ParserContext中
if (beanDefinition != null) {
BeanComponentDefinition componentDefinition =
new BeanComponentDefinition(beanDefinition,
AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
parserContext.registerComponent(componentDefinition);
}
}
这里可以看到AnnotationAwareAspectJAutoProxyCreator的BeanDefinition在第一步进行了注册,然后读取标签中的proxy-target-class和expose-proxy属性,并且将属性值设置到生成的BeanDefinition中。最后将生成的BeanDefinition注册到ParserContext中。这里我们继续看AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement))方法,其实现如下:
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
// 注册AnnotationAwareAspectJAutoProxyCreator类型的BeanDefinition
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class,
registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls,
BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 如果已经注册过AnnotationAwareAspectJAutoProxyCreator的Definition,如果其
// 和当前将要注册的BeanDefinition是同一个类型,则不再注册,如果不同,则判断其优先级比
// 当前将要注册的BeanDefinition要高,则将其类名设置为当前要注册的BeanDefinition的名称
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition =
registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
// 如果不存在已经注册的Aop的bean,则生成一个,并且设置其执行优先级为最高优先级,并且标识
// 该bean为Spring的系统Bean,设置完之后则对该bean进行注册
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的BeanDefinition的时候,首先会判断是否已经生成过该bean,这里不会将已经生成的bean进行覆盖;如果没有生成该bean,则创建一个并进行注册。这里需要说明的是,Spring注册该bean的时候使用的order是Ordered.HIGHEST_PRECEDENCE,这么设置的原因在于Spring使用该bean进行切面逻辑的织入,因而这个bean必须在所有用户自定义的bean实例化之前进行实例化,而用户自定义的bean的实例化优先级是比较低的,这样才能实现织入代理逻辑的功能。
本文首先使用一个简单的示例展示了Spring Aop的使用方式,然后对标签中的AnnotationAwareAspectJAutoProxyCreator
的BeanDefinition,关于Spring是如何使用该类实现代理的逻辑将在下一篇文章中进行讲解。