`

spring4.0源码分析━━━(AOP实现)

阅读更多
  • AOP的概念

         AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面)。这就让一些问题很简单化了,例如:开始我们实现了一些逻辑并上线了,现在客户又来了一个新的需求。要在每次交易之前统计下,或者记录下他们的交易简单资料。而你发现你其他模块可能正好有这部分的功能。那AOP就可以用得上了,使用AOP就可以在不修改源代码的情况下新增这些功能。就是在交易前这个切面,新装你的一些功能。这有点像拦截器和Filter。其实都是一个原理。前面说了解析xml和Bean的实例化。

         而AOP的实现的话都是在我前面两篇spring3.0源码分析的基础上实现。其实AOP算是对自己本身IOC的实例,你学好弄懂AOP。基本IOC的也是懂了。但是这里的AOP也用到了一些新的东西,像Aspect,还有JVM的反射和动态代理。还有CGLIB这里也是有用到的。但是默认的实现是用JVM的动态代理。

 

  • AOP的实例

        AOP用起来还是很简单的。就把xml配置好就算完工了。有Advisor和aspect两种方式来完成。如果是用Advisor的话需要实现AfterReturningAdvice,MethodBeforeAdvice,ThrowsAdvice等接口。而如果用aspect的话则不用继承或者实现其他的类,一个普通的类即可。

     

public class LogAop {
	private final static Log log = LogFactory.getLog(LogAop.class);
	public void addLog(){
		log.info("add log ========================");
	}
}

 

public class BeforeAdvisor implements MethodBeforeAdvice {
	private final static Log log =LogFactory.getLog(BeforeAdvisor.class);
	
	private int testSEL;

	@Override
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		log.info("in before advice and method="+method.getName()+ " args "+args.length);
	}
 ..........

 

public class AfterAdvisor implements AfterReturningAdvice {
	private final static Log log =LogFactory.getLog(AfterAdvisor.class);
	
........

	@Override
	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		// TODO Auto-generated method stub
		log.info("test sel the testSEL "+testSEL);
		log.info("after return advice");
	}

}

 

 

     而配置文件如下:

	<bean id="LogAop" class="com.zzx.study.aop.LogAop" />
	<bean id="beforeAdvisor" class="com.zzx.study.aop.BeforeAdvisor" >
	   <property name="testSEL" value="11"/>
	</bean>
	<bean id="beforeAdvisor2" class="com.zzx.study.aop.BeforeAdvisor2" >
	   <property name="testSEL" value="23"/>
	</bean>
	<bean id="afterAdvisor" class="com.zzx.study.aop.AfterAdvisor" >
	   <property name="testSEL" value="11"/>
	</bean>
	<aop:config>
	   <aop:pointcut expression="execution(* com.zzx.study.di.BankSecurityDaoImpl.add(..))" id="target" />
	   <aop:pointcut expression="execution(* com.zzx.study.di.Ban*.ad*(..))" id="nonePointCutTest" />
	   <aop:advisor id="bid" pointcut-ref="target" advice-ref="beforeAdvisor" />
	   <aop:advisor id="noAdvisor" pointcut-ref="nonePointCutTest" advice-ref="beforeAdvisor2" />
	   <aop:advisor id="aid" pointcut-ref="target" advice-ref="afterAdvisor" />
	   <aop:aspect ref="LogAop" >
	       <aop:after method="addLog"  pointcut-ref="target"/>
	   </aop:aspect>
	</aop:config>  

       向上面实现后则如果执行BankSecurityDaoImpl的add方法前就会执行BeforeAdvisor的before方法,然后执行add方法,最后是LogAop的addLog方法,AfterAdvisor的afterReturning方法。这里还可以让Advisor实现Order定义这些执行的前后。

public class BeforeAdvisor implements MethodBeforeAdvice,Ordered {
	............

	@Override
	public int getOrder() {
		// TODO Auto-generated method stub
		return 2;
	}

}

 

      这里的有一个getOrder方法,返回int值,越小则越先执行。

 

  • AOP在spring中的实现

       在解析xml的时候说过,如果发现不是bean标签,则会是不同的类来解析。解析aop的为http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler。也就是AopNamespaceHandler类。进去到AopNamespaceHandler类中parse方法,实际是调用其父类的NamespaceHandlerSupport的parse方法。

private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
		String localName = parserContext.getDelegate().getLocalName(element);
		BeanDefinitionParser parser = this.parsers.get(localName);
		if (parser == null) {
			parserContext.getReaderContext().fatal(
					"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
		}
		return parser;
}

 这里的parses是在解析xml的时候初始化。

public void init() {
		// In 2.0 XSD as well as in 2.1 XSD.
		registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
		registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
		registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

		// Only in 2.0 XSD: moved to context namespace as of 2.1
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}

 

 

 如果是config标签,则是用ConfigBeanDefinitionParser类了,如果是aspectj-autoproxy标签则是用AspectJAutoProxyBeanDefinitionParser类来解析了。其实这两个的解析最终都是向DefaultListableBeanFactory中注册class为AspectJAwareAdvisorAutoProxyCreator的BeanDefinition。而AspectJAwareAdvisorAutoProxyCreator是有实现BeanPostProcessor、BeanFactoryAware接口的。而实例化一个bean的时候会经过这些BeanPostProcessor的处理。也就是这些BeanPostProcessor最终实现了把目标对象代理掉,而用代理前后spring就会调用到配置的这些Advisor来处理一些业务逻辑了。其中的BeanFactoryAware接口是把BeanFactory注入到AspectJAwareAdvisorAutoProxyCreator这个类中,而最终执行方法前通过这里注入的BeanFactory得到这些Advisor类并调用。

 

这里讲使用java动态代理的实现。在JdkDynamicAopProxy类中。使用到了责任链的模式,会先得到一个Advisor的list,然后在list中用链的方式执行下去。如果chain不是空的则会到ReflectiveMethodInvocation类中执行processed方法。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MethodInvocation invocation;
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Class targetClass = null;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				return hashCode();
			}
			if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// May be null. Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}

			// Get the interception chain for this method.
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
			}
			else {
				// We need to create a method invocation...
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
}

 

 

public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

		Object interceptorOrInterceptionAdvice =
		    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
			    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				// Dynamic matching failed.
				// Skip this interceptor and invoke the next in the chain.
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
}

 

这里的interceptorOrInterceptionAdvice都是MethodInterceptor类型。因为解析xml的时候,会把<aop:advisor>最终生成class为DefaultBeanFactoryPointcutAdvisor类的BeanDefinition类,而<aop:aspect>会生成class为AspectJPointcutAdvisor的BeanDefinition。又通过DefaultAdvisorAdapterRegistry类把Advisor转换为MethodInterceptor类。

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

...........................


	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
		Advice advice = advisor.getAdvice();
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
	}

	public void registerAdvisorAdapter(AdvisorAdapter adapter) {
		this.adapters.add(adapter);
	}

}

    像beforeAdvisor则转换为MethodBeforeAdviceInterceptor这样的拦截器了。在这个拦截器中的invoke方法中会发现会先调用自己advice的before方法,也就是你自己实现的业务类。接着又会调用processed,也就是连接链的方式,一直调用下去,知道chain中所有都执行完成。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

	private MethodBeforeAdvice advice;


	/**
	 * Create a new MethodBeforeAdviceInterceptor for the given advice.
	 * @param advice the MethodBeforeAdvice to wrap
	 */
	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}

	public Object invoke(MethodInvocation mi) throws Throwable {
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
		return mi.proceed();
	}

}

     

       这里的advice

 

 

 

分享到:
评论

相关推荐

    Spring4.0从入门到精通AOP日志示例

    使用spring4.0进行用户日志的记录 这里带junit的测试跟main的测试 参考了 http://blog.csdn.net/oathevil/article/details/7288867 本代码中还包括了一个java自带注解的例子写的都非常易懂对于hellospring中第一位...

    AOP流程源码分析-SpringAOP中定义的类图

    AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析...

    Spring4.0+Hibernate4.0+Struts2.3整合案例

    Spring4.0+Hibernate4.0+Struts2.3整合案例:实现增删改查。 ===================== application.xml: xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=...

    Spring-Aop源码实现

    Spring-Aop源码实现

    Spring AOP源码分析.mmap

    有关于Spring,我们最常用的两个功能就是IOC和AOP,前几篇文章从源码级别介绍了Spring容器如何为我们生成bean及bean之间的依赖关系... 确实,Spring也就是通过这两种方式来实现AOP相关功能,下面就通过源码来简单求证下

    Spring 4.0 AOP 面向切面Maven测试程序

    Spring 4.0 AOP 面向切面测试程序,涉及通知类型包括前置通知\后置通知\返回通知\异常通知\环绕通知,项目采用Maven搭建!

    spring4.0和hibernate4.0整合框架

    spring4.0和hibernate4.0框架的标准整合,此框架实现了hibernate根据实体自动创建表(前提是你要在mysql中创建名为testspring的库),spring的aop拦截功能,帮助了解aop,和spring事物控制,异常回滚以及junit4的测试...

    spring源码分析(1-10)

    Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源代码解析(九):Spring Acegi框架鉴权的实现 Spring源代码解析(十):Spring Acegi框架授权...

    spring 4.0 相关jar

    spring mvc beans core webmvc aop jdbc 相关jar 下载

    基于注解实现SpringAop

    基于注解实现SpringAop基于注解实现SpringAop基于注解实现SpringAop

    Java流行框架源码分析:Spring源码、SpringBoot源码、SpringAOP源码、SpringSecurity源码、

    Java流行框架源码分析:Spring源码、SpringBoot源码、SpringAOP源码、SpringSecurity源码、SpringSecurity OAuth2源码、JDK源码、Netty源码

    spring4.0.zip

    框架: Spring 实现了使用简单的组件配置组合成一个复杂的应用. 在 Spring 中可以使用 XML 和 Java 注解组合这些对象 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库 (Spring ...

    Java spring AOP源码

    Java spring AOP源码

    Spring_aop源码

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象...

    spring aop spring aop

    spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop

    spring aop实现原理

    NULL 博文链接:https://zhang-yingjie-qq-com.iteye.com/blog/319927

    Spring AOP IOC源码笔记.pdf

    1.Spring入门和IOC介绍 2.对象依赖 3.AOP入门 4.JDBCTemplate和Spring事务 5.Spring事务原理 6.Spring事务的一个线程安全问题 7.IOC再回顾和面试题 8.AOP再回顾

    spring-aop.jar各个版本

    spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...

    使用Spring的注解方式实现AOP的细节

    使用Spring的注解方式实现AOP的细节

    五、Spring源码分析——Spring Aop

    NULL 博文链接:https://ylxy3058.iteye.com/blog/2224244

Global site tag (gtag.js) - Google Analytics