您的位置:首页 > 编程语言 > Java开发

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