1、简单使用 首先定义要拦截的bean,简单的写一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class CustomBean { private String str = "A" ; public String getStr () { return str; } public void setStr (String str) { this .str = str; } @Override public String toString () { return str; } }
之后定义切面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @Aspect public class CustomAspect { private final String POINT_CUT = "execution(* com.minivision.test.spring.AOP.test.CustomBean.*(..))" ; @Around(POINT_CUT) public Object around (ProceedingJoinPoint point) { System.out.println("around before" ); Object object = null ; try { object = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("around after" ); return object; } @Before(POINT_CUT) public void before () { System.out.println("before" ); } @After(POINT_CUT) public void after () { System.out.println("after" ); } }
其实使用注解会更简单,但是没有使用xml文档直观,因为是学习,所以使用xml配置文件: spring-aop.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?xml version="1.0" encoding="UTF-8" ?> <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" > <aop:aspectj-autoproxy /> <bean id ="customBean" class ="com.demo.CustomBean" /> <bean class ="com.demo.CustomAspect" /> </beans >
最后写个main方法测试:
1 2 3 4 5 public static void main (String[] arge) { ApplicationContext context = new ClassPathXmlApplicationContext ("spring-aop.xml" ); CustomBean bean = context.getBean("customBean" , CustomBean.class); System.out.println(bean.toString()); }
运行结果:
1 2 3 4 5 around before before around after after A
下面开始源码分析,首先需要从xml解析开始
由配置文件spring-aop.xml可知:标签aop:aspectj-autoproxy/ 的命名空间为:http://www.springframework.org/schema/aop, 所以从new ClassPathXmlApplicationContext(“spring-aop.xml”);层层深入源码,到达org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法, 会走delegate.parseCustomElement(ele);这个自定义解析逻辑。
下面看org.springframework.beans.factory.xml.BeanDefinitionParserDelegate类中的 parseCustomElement(Element ele)方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Nullable public BeanDefinition parseCustomElement (Element ele) { return parseCustomElement(ele, null ); } @Nullable public BeanDefinition parseCustomElement (Element ele, @Nullable BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null ) { return null ; } NamespaceHandler handler = this .readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null ) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]" , ele); return null ; } return handler.parse(ele, new ParserContext (this .readerContext, this , containingBd)); }
首先要获取NamespaceHandler,会在META-INF/spring.handlers中获取相应的类的全量名: spring-aop-5.1.8.RELEASE.jar中为:
1 http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
即获取的NamespaceHandler为:AopNamespaceHandler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 ()); }
当即解析标签aop:aspectj-autoproxy/ 的类为:AspectJAutoProxyBeanDefinitionParser, 之后调用parse方法:
1 2 3 4 5 6 7 8 9 10 @Override @Nullable public BeanDefinition parse (Element element, ParserContext parserContext) { BeanDefinitionParser parser = findParserForElement(element, parserContext); return (parser != null ? parser.parse(element, parserContext) : null ); }
即根据标签获取BeanDefinitionParser,这里为AspectJAutoProxyBeanDefinitionParser。 最后调用AspectJAutoProxyBeanDefinitionParser中的parse方法:
1 2 3 4 5 6 7 @Override @Nullable public BeanDefinition parse (Element element, ParserContext parserContext) { AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); extendBeanDefinition(element, parserContext); return null ; }
下面来分析这个AspectJAutoProxyBeanDefinitionParser的解析方法。