AOP, 即Aspect-Oriented-Programming, 面向切面編程, 又一Spring的核心,被普遍應用,如在Spring-tx中都有用到,其好處是實現鬆耦合的外圍處理程序,先說些理論吧。 java
例如其中BeforeAdvice的擴展接口MethodBeforeAdvice, 及該通知會在目標對象的目標方法調用以前被調用: 正則表達式
public interface MethodBeforeAdvice extends BeforeAdvice { void before(Method method, Object[] args, Object target) throws Throwable; }Spring爲MethodBeforeAdvice提供了一個簡單用於計數方法調用次數的實現CountingBeforeAdvice, 具體的計數實現由MethodCounter實現了:
public class CountingBeforeAdvice extends MethodCounter implements MethodBeforeAdvice { @Override public void before(Method m, Object[] args, Object target) throws Throwable { count(m); }
public class MethodCounter implements Serializable { private HashMap<String, Integer> map = new HashMap<String, Integer>(); private int allCount; protected void count(Method m) { count(m.getName()); } protected void count(String methodName) { Integer i = map.get(methodName); i = (i != null) ? new Integer(i.intValue() + 1) : new Integer(1); map.put(methodName, i); ++allCount; } ... }
看其中的AbstractRegexpMethodPointcut,它有一個模版方法matchesPatterns, 就是先匹配包括的方法,再匹配不包括的方法,都由子類來實現,如JdkRegexpMethodPointcut的實現。 spring
protected boolean matchesPattern(String signatureString) { for (int i = 0; i < this.patterns.length; i++) { boolean matched = matches(signatureString, i); if (matched) { for (int j = 0; j < this.excludedPatterns.length; j++) { boolean excluded = matchesExclusion(signatureString, j); if (excluded) { return false; } } return true; } } return false; }
對應JdkRegexpMethodPointcut的實現: 編程
protected boolean matches(String pattern, int patternIndex) { Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern); return matcher.matches(); } protected boolean matchesExclusion(String candidate, int patternIndex) { Matcher matcher = this.compiledExclusionPatterns[patternIndex].matcher(candidate); return matcher.matches(); }
到此將了aop中的幾個重要組件概念,接下來是如何實現aop。 app
這就要涉及到核心的ProxyFactoryBean了: ide
那麼ProxyFactoryBean是怎麼來產生代理對象的呢,以下: 模塊化
public Object getObject() throws BeansException { initializeAdvisorChain(); //初始化通知鏈, 爲Proxy代理對象配置Advisor鏈 if (isSingleton()) { return getSingletonInstance(); } else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } return newPrototypeInstance(); } }
看看initializeAdvisorChain方法: 函數
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { if (this.advisorChainInitialized) { //若是已經初始化了,就返回 return; } if (!ObjectUtils.isEmpty(this.interceptorNames)) { ... // Materialize interceptor chain from bean names. for (String name : this.interceptorNames) { //這個interceptorNames是咱們xml中配置的通知器(攔截器)bean的name if (logger.isTraceEnabled()) { logger.trace("Configuring advisor or advice '" + name + "'"); } if (name.endsWith(GLOBAL_SUFFIX)) { ... else { // If we get here, we need to add a named interceptor. // We must check if it's a singleton or prototype. Object advice; if (this.singleton || this.beanFactory.isSingleton(name)) { // Add the real Advisor/Advice to the chain. advice = this.beanFactory.getBean(name); } else { // It's a prototype Advice or Advisor: replace with a prototype. // Avoid unnecessary creation of prototype bean just for advisor chain initialization. advice = new PrototypePlaceholderAdvisor(name); } addAdvisorOnChainCreation(advice, name); } } } this.advisorChainInitialized = true; }再看看ProxyFactoryBean怎麼生成單例代理對象的:
private synchronized Object getSingletonInstance() { if (this.singletonInstance == null) { this.targetSource = freshTargetSource(); if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { // Rely on AOP infrastructure to tell us what interfaces to proxy. Class targetClass = getTargetClass(); if (targetClass == null) { throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy"); } setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); } // Initialize the shared singleton instance. super.setFrozen(this.freezeProxy); this.singletonInstance = getProxy(createAopProxy()); //這裏就經過createAopProxy來建立咱們的代理對象了 } return this.singletonInstance; }接着看看createAopProxy(), 其默認實現是DefaultAopProxyFactory.java, 兩種代理對象的實現JdkDynamicAopProxy和CglibProxy:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class targetClass = config.getTargetClass(); // 這裏獲取xml中配置的目標對象 if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } return CglibProxyFactory.createCglibProxy(config); } else { return new JdkDynamicAopProxy(config); } }
JdkDynamicAopProxy是內部怎麼建立代理對象的呢? 測試
public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
JdkDynamicAopProxy實現了JDK動態代理的標準接口InvocationHandler,當咱們調用目標代理對象時會直接調用invoke方法: ui
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ... 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(); } ... }真正攔截器處理就時invocation.proceed()方法了:
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); } }
這就是JdkDynamicAopProxy生成目標代理對象的實現過程,那麼cglib怎麼實現的呢,看DynamicAdvisedIntercept的intercept方法:
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { ... target = getTarget(); if (target != null) { targetClass = target.getClass(); } List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { retVal = methodProxy.invoke(target, args); //沒有配置攔截器 } else { // We need to create a method invocation... retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); //攔截器鏈處理 } retVal = processReturnType(proxy, target, method, retVal); return retVal; }
至此,簡單講解了Spring Aop代理對象的實現過程。
說了這麼多,仍是要得有個demo才行, 這裏咱們會對目標對象創建一條具備2個攔截器的攔截鏈:
package org.spring.framework.learn.aop; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; /** * 定製的後置通知,用於注入Advisor */ public class MyAdvice implements AfterReturningAdvice{ @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("I am MyAdvice, invoked after target method return."); } }
package org.spring.framework.learn.aop; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** * Advisor Test Class */ public class MyInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("I am MyInterceptor, invoked before target method execute."); return invocation.proceed(); } }
package org.spring.framework.learn.aop; import org.springframework.aop.support.JdkRegexpMethodPointcut; /** * 定製的PointCut, 用於注入Advisor * */ public class MyPointCut extends JdkRegexpMethodPointcut { private static final long serialVersionUID = 1L; }
package org.spring.framework.learn.aop; import org.springframework.aop.support.DefaultPointcutAdvisor; /** * 定製的通知器 */ public class MyAdvisor extends DefaultPointcutAdvisor { private static final long serialVersionUID = 1L; }
package org.spring.framework.learn.aop; public interface MyService { public void helloAop(); }
package org.spring.framework.learn.aop; public class MyServiceImpl implements MyService{ public void helloAop(){ System.out.println("This is a target for aop handle."); } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <!-- 定製後置通知,並注入到Advisor中 --> <bean id="myAdvice" class="org.spring.framework.learn.aop.MyAdvice" /> <!-- 定製切入點, 匹配方法,並注入到Advisor --> <bean id="myPointCut" class="org.spring.framework.learn.aop.MyPointCut"> <property name="pattern" value="org.spring.framework.learn.aop.MyServiceImpl.*" /> </bean> <!-- 定製Advisor, 用於對目標對象實現擴展 --> <bean id="myAdvisor" class="org.spring.framework.learn.aop.MyAdvisor"> <!-- 通知 --> <property name="advice"> <ref bean="myAdvice"/> </property> <!-- 切點 --> <property name="pointcut"> <ref bean="myPointCut"/> </property> </bean> <!-- 攔截器用於攔截目標對象,也用於對象加強 --> <bean id="myInterceptor" class="org.spring.framework.learn.aop.MyInterceptor"/> <!-- 代理對象配置 --> <bean id="myAopProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>org.spring.framework.learn.aop.MyService</value> </property> <property name="target"> <bean class="org.spring.framework.learn.aop.MyServiceImpl"></bean> </property> <!-- --> <property name="interceptorNames"> <list> <value>myInterceptor</value> <value>myAdvisor</value> </list> </property> </bean> </beans>
public class ProxyFactoryBeanTests { private static ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("configs/aop-test.xml"); @Test public void testProxyFactoryBean1(){ MyService in = (MyService)context.getBean("myAopProxy"); in.helloAop(); } }
收工,不懂留話。