spring aop理解二:spring aop 注册和创建代理
2017-01-11 23:56
405 查看
注解方式 使用指南
引入spring基本的依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version> </dependency>
spring xml配置
<?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:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <context:component-scan base-package="com.ly"/> <bean id="userService" class="com.ly.examples.spring.ioc.UserServiceImpl" p:userDao-ref="userDao"/> <bean id="userDao" class="com.ly.examples.spring.ioc.UserDaoImpl" scope="prototype" /> <aop:aspectj-autoproxy ></aop:aspectj-autoproxy> <!--<aop:config>--> <!--<aop:pointcut id="anyMethod" expression="execution(* com.ly.examples.spring.ioc.UserService.queryByName(..))"></aop:pointcut>--> <!--<aop:aspect id="logAndExecuteTime" ref="simpleLogAndExecuteTimeAspectWithXml">--> <!--<aop:before method="before" pointcut-ref="anyMethod"></aop:before>--> <!--<aop:after method="after" pointcut-ref="anyMethod"></aop:after>--> <!--<aop:around method="around" pointcut-ref="anyMethod"></aop:around>--> <!--</aop:aspect>--> <!--</aop:config>--> </beans>
上面 会激活AspectJAwareAdvisorAutoProxyCreator。
编写切面类
@Component @Aspect public class SimpleLogAndExecuteTimeAspect { @Pointcut("execution(* *.queryByName(..))") public void anyMethod(){} // JoinPoint 表示 连接点 注意 aspetct 中 的切点 和连接点的区别 @Before("anyMethod()") public void before(JoinPoint joinPoint){ //打印日志 什么 方法 几点 被执行 System.out.println("Signature"+joinPoint.getSignature().getName()+";start time:"+System.currentTimeMillis()); } @After("anyMethod()") public void after(JoinPoint joinPoint){ //打印日志 什么 方法 几点 被执行 System.out.println("Signature"+joinPoint.getSignature().getName()+";end time:"+System.currentTimeMillis()); } @Around("anyMethod()") public void around(ProceedingJoinPoint joinPoint){ try { long s = System.currentTimeMillis(); joinPoint.proceed(); long e = System.currentTimeMillis(); System.out.println("方法耗时:"+(e-s)/1000); } catch (Throwable throwable) { throwable.printStackTrace(); } } }
编写测试类
public class TestAop { public static void main(String[] args) { testBeanFactory(); } private static void testBeanFactory() { ClassPathXmlApplicationContext fac = new ClassPathXmlApplicationContext("META-INF/spring/test.xml"); UserService us = fac.getBean(UserService.class); us.queryByName("xuhaitao"); } }
运行结果
SignaturequeryByName;start time:1484149383675 SignaturequeryByName;start time:1484149383676 方法耗时:0 SignaturequeryByName;end time:1484149383676 方法耗时:0 SignaturequeryByName;end time:1484149383676
执行两次 是因为我的UserServiceImpl 里面调用的userDao也被拦截了一次。
public class UserServiceImpl implements UserService { private UserDao userDao; @Override public User queryByName(String name) { return userDao.queryByName(name); } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
源码分析
<aop:aspectj-autoproxy/>
aop:aspectj-autoproxy标签的目的是: 将spring的需要代理的bean ,织入advice ,自动创建代理。下面我们分析改标签做了什么。所有标签解析 都是调用BeanDefinitionParser的parse方法。
通过搜索源码我们知道该标签被AspectJAutoProxyBeanDefinitionParser解析的。如下
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
我们来看下他的parse方法:
public BeanDefinition parse(Element element, ParserContext parserContext) { //注册AnnotationAwareAspectJAutoProxyCreator AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); //对于注解子类元素的处理 this.extendBeanDefinition(element, parserContext); return null; }
我们重点看registerAspectJAnnotationAutoProxyCreatorIfNecessary方法:
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); registerComponentIfNecessary(beanDefinition, parserContext); }
三句代码做了三件事:
1. 注册或升级AspectJAnnotationAutoProxyCreator
这个方法也不复杂 直接想bean容器注册了AspectJAnnotationAutoProxyCreator beanDefinition ,如果已经存在
(根据beanName=org.springframework.aop.config.internalAutoProxyCreator判断),看存在class的优先级是,如果低,更新为AspectJAnnotationAutoProxyCreator 。
处理proxy-target-class 和expose-proxy 属性
proxy-target-class :表示是否采用cglib动态代理类形式,默认false,也就是采用jdk的动态代理,如果需要代理的类没有实现一个接口,jdk动态代理是不起作用的,所以可以采用cglib。这里的方法只是将上面注册的beanDefinition 添加proxyTargetClass属性值。
expose-proxy:表示是否暴漏proxy类,为了解决动态代理内部调用不起作用的问题。
class A { public void funA(){ funB(); } //被代理 public void funB(){ ... } } 这时候funA是不起作用的,启用expose-proxy=true 然后更改funA: public void funA(){ ((A)AopContext.currentProxy()).funB(); }
注册组件并通知,便于监听器做进一步处理
略过
到此AspectJAnnotationAutoProxyCreator 的注册已经说完了。
AspectJAnnotationAutoProxyCreator创建proxy
AspectJAnnotationAutoProxyCreator 实现了BeanPostProcessor,所以我们直接看他的postProcessAfterInitialization。public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(bean != null) { Object cacheKey = this.getCacheKey(bean.getClass(), beanName); if(!this.earlyProxyReferences.contains(cacheKey)) { return this.wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
主要实现在wrapIfNecessary 方法,根据需要创建代理
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // if(beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; //advisedBeans 存放处理过的bean是否应用了代理 } else if(Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; //isInfrastructureClass判断该bean是否是aop的基础类 如Advice.class,PointCut.class etc //shouldSkip 检查是否应该跳过 } else if(!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) { //寻找合适的AdvicesAndAdvisors Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null); if(specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); //创建代理 Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } else { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } } else { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } }
上面有两个方法我们比较关心
1.getAdvicesAndAdvisorsForBean:怎么找到拦截器的specificInterceptors
2.createProxy:具体怎么创建
先看下getAdvicesAndAdvisorsForBean:
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) { List advisors = this.findEligibleAdvisors(beanClass, beanName); return advisors.isEmpty()?DO_NOT_PROXY:advisors.toArray(); }
直接看findEligibleAdvisors:
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { //找到全部的advisors List candidateAdvisors = this.findCandidateAdvisors(); //关键方法 List eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); this.extendAdvisors(eligibleAdvisors); if(!eligibleAdvisors.isEmpty()) { eligibleAdvisors = this.sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
findAdvisorsThatCanApply:
protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); List var4; try { //关键方法 var4 = AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName((String)null); } return var4; }
再看 AopUtils.findAdvisorsThatCanApply
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if(candidateAdvisors.isEmpty()) { return candidateAdvisors; } else { LinkedList eligibleAdvisors = new LinkedList(); Iterator hasIntroductions = candidateAdvisors.iterator(); while(hasIntroductions.hasNext()) { Advisor candidate = (Advisor)hasIntroductions.next(); if(candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions1 = !eligibleAdvisors.isEmpty(); Iterator candidate2 = candidateAdvisors.iterator(); while(candidate2.hasNext()) { Advisor candidate1 = (Advisor)candidate2.next(); if(!(candidate1 instanceof IntroductionAdvisor) && canApply(candidate1, clazz, hasIntroductions1)) { eligibleAdvisors.add(candidate1); } } return eligibleAdvisors; } }
我们不再往下看了 大概逻辑就是判断 point 是否匹配 class类的其中一个方法匹配。
下面我们看下面的代码具体怎么创建
Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) { if(this.beanFactory instanceof ConfigurableListableBeanFactory) { //更新beanName 在beanfactory中的beandefinition 的originalTargetClass属性为beanClass AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass); } ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); if(!proxyFactory.isProxyTargetClass()) { if(this.shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { this.evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors); Advisor[] var7 = advisors; int var8 = advisors.length; for(int var9 = 0; var9 < var8; ++var9) { Advisor advisor = var7[var9]; proxyFactory.addAdvisor(advisor); } proxyFactory.setTargetSource(targetSource); this.customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if(this.advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } return proxyFactory.getProxy(this.getProxyClassLoader()); }
相关文章推荐
- Spring AOP的实现原理之代理创建
- 深入理解Spring AOP之二代理对象生成
- Spring AOP 演化过程(二):基于代理的经典Spring AOP
- Spring-AOP 自动创建代理之AnnotationAwareAspectJAutoProxyCreator
- 译-Spring-理解AOP代理
- 什么是spring,spring的优缺点,AOP和IOC的理解,spring的动态代理
- Spring AOP 自动创建代理
- Spring3.1.0实现原理分析(九).AOP创建代理对象的过程
- spring基础概念AOP与动态代理理解
- Spring-AOP 自动创建代理之DefaultAdvisorAutoProxyCreator
- 【Spring AOP】自动创建代理
- 关于spring.net的面向切面编程 (Aspect Oriented Programming with Spring.NET)-使用工厂创建代理(Using the ProxyFactoryObject to create AOP proxies)
- Spring - 动态代理 与 AOP 理解
- Spring3.1.0实现原理分析(九).AOP之创建代理对象的过程
- Spring AOP(创建切面理解)1
- spring aop(五)--ProxyFactoryBean创建代理的实现
- JDK动态代理(Spring AOP理解的基础)
- Spring源码之创建AOP代理(补)
- Spring-AOP 自动创建代理
- 深入理解Spring AOP之二代理对象生成