1、SpringAOP的aop命名空间的基本使用
1.1、非AspectJ注解的使用形式
目标bean定义
<bean id="aopNameSpaceTestBean" class="com.wzy.springstudy.aop.AutoProxyCreator.aopnamespace.AopNameSpaceTestBean"/>
aspect bean定义 非注解方式,就是普通的类
<bean id="aspectJBean" class="com.wzy.springstudy.aop.AutoProxyCreator.aopnamespace.AspectJBean"/>
aop配置
<aop:config proxy-target-class="true">
<aop:aspect ref="aspectJBean" order="1">
<aop:pointcut id="aspectPointcut" expression="execution(* com.wzy.springstudy.aop.AutoProxyCreator.aopnamespace.AopNameSpaceTestBean.test())"/>
<aop:before pointcut-ref="aspectPointcut" method="sayHello"/>
</aop:aspect>
</aop:config>
public class AopNameSpaceTestBean {
public void test(){
System.out.println("ttttttttt");
}
}
public class AspectJBean {
public void sayHello(){
System.out.println("hello");
}
}
@Test
public void testAopNameSpace(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context-aopAutoCreator.xml");
com.wzy.springstudy.aop.AutoProxyCreator.aopnamespace.AopNameSpaceTestBean aopNameSpaceTestBean = (AopNameSpaceTestBean) ctx.getBean("aopNameSpaceTestBean");
aopNameSpaceTestBean.test();
}
输出:
hello 逻辑织入成功
ttttttttt
1.2、AspectJ注解的使用形式
使用AspectJ的注解定义好切面,然后在xml中添加:<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/> 即可。
2、aop命名空间的实现原理分析
2.1、AopNamespaceHandler源码:
public class AopNamespaceHandler extends NamespaceHandlerSupport {
/**
* Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
* '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
* and '{@code scoped-proxy}' tags.
*/
init方法的执行时机是xml文件解析的时候
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
添加一个ConfigBeanDefinitionParser bean定义解析器,专门用于解析<aop:config 及其子标签
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
添加一个AspectJAutoProxyBeanDefinitionParser同于注册一个AspectJAutoProxyBeanDefinitionParser用于解析<aop:aspectj-autoproxy标签
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
添加一个ScopedProxyBeanDefinitionDecorator 用于解析 <aop:scoped-proxy标签
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
2.2、我们先来查看非AspectJ注解的使用形式原理,我们主要查看的是ConfigBeanDefinitionParser类因为它是用来解析<aop:config标签的,其源码如下:我们主要看它的parse()方法
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
配置一个代理自动构建器,这里构建的是AspectJAwareAdvisorAutoProxyCreator构建器 非注解的AspectJ的代理构建器!!!!!
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
解析<aop:pintcut 元素,生成一个BeanDefinition实例注册到BeanDefinitionRegistry中
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
解析<aop:advisor 元素,生成一个BeanDefinition实例注册到BeanDefinitionRegistry
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
解析<aop:aspect 元素,生成一个BeanDefinition实例注册到BeanDefinitionRegistry
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
实现就是这么简单,解析标签 生成响应的BeanDefinition实例注册到容器中。
2.3、AspectJ注解的使用形式的实现原理
这种使用方法比较简洁,也是推荐的使用方式,其实现原理也很简单,就是像容器中注册一个基于AspectJ注解形式处理的代理自动构建器AnnotationAwareAspectJAutoProxyCreator 我们来查看AspectJAutoProxyBeanDefinitionParser的源码,同样也是查看其parse()方法:
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
最终就只是需要注册一个AnnotationAwareAspectJAutoProxyCreator的beanDefinition的实例到IOC容器中即可。
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
3、SpringAOP总结:
1、我们通过4篇博客讲解了SpringAop的基本使用以及实现原理,主要讲解的东西有AOP的基本定义、AOP术语的解释、SpringAOP的代理技术、SpringAOP对AspectJ的语法支持。
2、重点讲解了代理自动构建器AbstractAutoProxyCreator 以及主要的实现:
BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator、AnnotationAwareAspectJAutoProxyCreator
3、AopNameSpaceHandler 的主要实现方式。
对于SpringAOP内部实现的一些经典的切点以及切面我们不做太多解释,还有AspectJ的一些切点表达式函数我们也没有太多的提及,因为这些东西是需要记忆的,我们只需要以查字典的方式去查找使用即可,我们还是主要偏向于整体的实现。