AOP爲Aspect Oriented Programming的縮寫,意爲:面向切面編程(也叫面向方面)。這就讓一些問題很簡單化了,例如:開始咱們實現了一些邏輯並上線了,如今客戶又來了一個新的需求。要在每次交易以前統計下,或者記錄下他們的交易簡單資料。而你發現你其餘模塊可能正好有這部分的功能。那AOP就能夠用得上了,使用AOP就能夠在不修改源代碼的狀況下新增這些功能。就是在交易前這個切面,新裝你的一些功能。這有點像攔截器和Filter。其實都是一個原理。前面說了解析xml和Bean的實例化。 java
而AOP的實現的話都是在我前面兩篇spring3.0源碼分析的基礎上實現。其實AOP算是對本身自己IOC的實例,你學好弄懂AOP。基本IOC的也是懂了。可是這裏的AOP也用到了一些新的東西,像Aspect,還有JVM的反射和動態代理。還有CGLIB這裏也是有用到的。可是默認的實現是用JVM的動態代理。 spring
AOP用起來仍是很簡單的。就把xml配置好就算完工了。有Advisor和aspect兩種方式來完成。若是是用Advisor的話須要實現AfterReturningAdvice,MethodBeforeAdvice,ThrowsAdvice等接口。而若是用aspect的話則不用繼承或者實現其餘的類,一個普通的類便可。 express
- 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定義這些執行的先後。 app
Java代碼
- public class BeforeAdvisor implements MethodBeforeAdvice,Ordered {
- ............
-
- @Override
- public int getOrder() {
- // TODO Auto-generated method stub
- return 2;
- }
-
- }
這裏的有一個getOrder方法,返回int值,越小則越先執行。 ide
在解析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的時候初始化。 this
- 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類並調用。 lua
這裏講使用java動態代理的實現。在JdkDynamicAopProxy類中。使用到了責任鏈的模式,會先獲得一個Advisor的list,而後在list中用鏈的方式執行下去。若是chain不是空的則會到ReflectiveMethodInvocation類中執行processed方法。 spa
- 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