`

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源代码

    3. **类型安全的依赖注入(Type-safe Dependency Injection)**:Spring4.0引入了`@Autowired`注解的`@Qualifier`注解,使得依赖注入更加类型安全,可以指定具体实现类,避免了因类型匹配错误导致的问题。...

    Spring4.0的jar包,官方源码,javadoc

    源码分析是提升技能的绝佳途径,Spring4.0的源码揭示了框架内部的工作机制。例如,你可以看到AOP(面向切面编程)如何实现、IoC(控制反转)容器如何管理Bean、以及事件监听和事务管理的底层逻辑。通过阅读源码,...

    spring4.0源码

    以下是对Spring 4.0源码的详细分析: 1. **核心容器**: - **BeanFactory与ApplicationContext**:Spring的核心是BeanFactory,它是管理对象(beans)的工厂。在4.0中,对BeanFactory和ApplicationContext进行了...

    spring-frameword4.0源码

    《Spring Framework 4.0源码深度解析》 Spring Framework是Java开发中广泛使用的轻量级框架,它为创建高效、灵活且可测试的应用程序提供了基础。Spring 4.0版本是一个重要的里程碑,引入了许多改进和新特性,使得...

    spring4.0 mybaties

    当Spring 4.0与MyBatis结合使用时,可以实现数据访问的高效管理,为开发者带来极大的便利。本文将详细介绍如何在Spring 4.0环境下整合MyBatis,以及它们的协同工作原理。 1. **Spring 4.0概述** Spring 4.0是...

    JEEBBS 4.0 源码包

    在JEEBBS 4.0源码中,你可以看到Java语言如何应用于构建动态、交互式的Web应用程序。 **三、源码结构分析** 1. **src目录**:这是源代码的主要存放地,通常包含Java类文件和其他资源。开发者可以在这里找到JEEBBS ...

    spring3.0 源码

    总之,Spring 3.0源码的深度分析有助于我们理解Spring框架的设计理念,掌握其核心功能的实现原理,从而更好地利用Spring进行软件开发。通过学习源码,我们可以学到如何优雅地实现IoC、AOP、MVC等设计模式,以及如何...

    精通Spring+4.x++企业应用开发实战(pdf)及源码

    10. **源码分析**:书中提供的源码有助于读者深入理解Spring框架的工作原理,通过实践加深理论知识,提升开发技能。 通过学习《精通Spring 4.x企业应用开发实战》,开发者不仅能掌握Spring的核心概念和技术,还能...

    spring-cglib-repack-3.1.jar,spring-objenesis-repack-2.1.jar

    在Java开发领域,Spring框架是不可或缺的一个部分,它为构建企业级应用提供了强大的支持。当我们在研究或编译Spring 4.0的源码时,可能会遇到...在进行Spring源码分析或自定义编译时,务必确保这两个jar包的正确引入。

    spring-framework-4.0.x

    4. **源码分析** - **Bean的创建与管理**:解析XML或注解配置,通过DefaultListableBeanFactory实现bean的实例化、初始化和依赖注入。 - **AOP实现**:通过ProxyFactoryBean或AspectJ自动代理实现切面编程。 - **...

    spring-framework-4.0.3.RELEASE-dist.zip

    文件名“spring-framework-4.0.3.RELEASE”包含了Spring框架的完整源代码、文档和示例,开发者可以通过分析源码学习Spring的工作原理,或者参考文档了解如何在实际项目中应用这些新特性。源码目录结构通常包括以下...

    spring3.0源码

    在本文中,我们将深入探讨Spring 3.0的核心概念和源码分析,以及如何在Eclipse环境中使用Maven进行部署。 1. **模块化设计**: Spring 3.0引入了模块化结构,将框架拆分为多个可选模块,如Core Container(核心...

    Spring 实战 (中文第4版) PDF + source code

    8. **源码分析**:"SpringiA4_SourceCode"可能包含了书中示例的源代码,读者可以通过阅读和运行这些代码来深入理解Spring框架的工作原理和最佳实践。 9. **PDF阅读**:"Spring实战(第4版).epub"是电子书格式,...

    基于Spring框架的电子商务平台源码

    "spring"标签表明项目的核心是Spring框架,而"电子商务架构"则意味着这个源码实现了一个完整的电商系统结构,包括用户管理、商品展示、购物车、订单处理、支付集成等关键功能模块。电子商务架构的设计需要考虑系统的...

    spring+mybatis企业应用实战项目源码(源码+sql)

    通过对源码的分析,可以了解如何在实际项目中组织和实现这些层次。 6. **SQL文件**:源码中的SQL文件用于创建和初始化数据库表结构,以及填充初始数据。这可以帮助开发者理解数据库设计和数据操作的方式。 7. **...

    spring-framework-5.2.x.zip

    压缩包内的源码分析将帮助我们理解Spring框架的内部工作机制,包括Bean工厂、ApplicationContext、AOP代理等核心组件。通过阅读源码,我们可以学习到如何利用IoC容器管理对象,如何实现AOP拦截器,以及如何自定义...

    hession例子,源码,最新的jar包,还有web例子与spring结合的例子

    3. **源码分析**: 深入理解Hessian源码对于优化和定制Hessian服务非常重要。源码可能包含了Hessian序列化和反序列化的实现细节,以及处理异常和错误的方式。通过阅读源码,你可以了解到Hessian如何处理不同类型的...

    ssh框架整合Extjs4.0示例,完整系统

    Spring提供了依赖注入,使得对象的创建和管理变得更加灵活,同时通过AOP支持实现代码的解耦。 2. **Struts2**:作为MVC(Model-View-Controller,模型-视图-控制器)设计模式的实现,Struts2负责处理HTTP请求,协调...

    spring-framework-4.0.0.RELEASE.7z

    Spring框架是Java开发中最广泛应用的轻量级框架之一,它以其模块化、...通过阅读和分析`spring-framework-4.0.0.RELEASE`源码,开发者可以深入了解Spring的工作机制,提升自己的技能,同时为解决实际问题提供理论支持。

    cztv_framework

    通过研究源码,我们可以深入了解如何在实践中应用Spring 4.0的各种特性。同时,文档可能包含了项目结构、使用指南以及开发注意事项,这对于理解和使用该框架至关重要。 总结来说,“cztv_framework”是一个基于...

Global site tag (gtag.js) - Google Analytics