前言
接上一篇从零开始造Spring08—AOP(介绍以及实现ReflectiveMethodInvocation和AopProxyFactory),这篇文章我们接着来讲Spring的AOP的JDK代理,这是学习刘欣老师的《从零开始造Spring》的学习笔记。
JDK代理的说明
与Cglib代理有所不同的是,JDK代理是针对接口的代理。所有要使用JDK代理必须要有接口。
测试类
public interface IPetStoreService { void placeOrder(); } @Component(value = "petStoreService") public class PetStoreService implements IPetStoreService { public PetStoreService() { } @Override public void placeOrder() { System.out.println("place order"); MessageTracker.addMsg("place order"); } }
XML中的配置
<context:component-scan base-package="com.jay.spring.service.v6"> </context:component-scan> <!--作为一个切面--> <bean id="tx" class="com.jay.spring.tx.TransactionManager" /> <aop:config> <aop:aspect ref="tx"> <!--切点--> <aop:pointcut id="placeOrder" expression="execution(* com.jay.spring.service.v6.*.placeOrder(..))" /> <aop:after-throwing pointcut-ref="placeOrder" method = "rollback"/> <aop:after-returning pointcut-ref="placeOrder" method="commit" /> <aop:before pointcut-ref="placeOrder" method="start" /> </aop:aspect> </aop:config>
JdkAopProxyFactory 类
public class JdkAopProxyFactory implements AopProxyFactory,InvocationHandler { private static final Log logger = LogFactory.getLog(JdkAopProxyFactory.class); private final AopConfig aopConfig; public JdkAopProxyFactory(AopConfig config) { Assert.notNull(config, "AdvisedSupport must not be null"); if (config.getAdvices().size() == 0) { throw new AopConfigException("No advice specified"); } this.aopConfig = config; } /** * 获取代理 * @return */ @Override public Object getProxy() { return getProxy(ClassUtils.getDefaultClassLoader()); } @Override public Object getProxy(ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.aopConfig.getTargetObject()); } Class<?>[] proxiedInterfaces = aopConfig.getProxiedInterfaces(); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 获取目标对象 Object target = this.aopConfig.getTargetObject(); Object retVal; // Get the interception chain for this method. //获取通知点 List<Advice> chain = this.aopConfig.getAdvices(method); // 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 = method.invoke(target, args); } else { List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(); interceptors.addAll(chain); // We need to create a method invocation... retVal = new ReflectiveMethodInvocation(target, method, args, interceptors).proceed(); } // Massage return value if necessary. /*Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType.isInstance(proxy) ) { // 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; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); }*/ return retVal; } }
说明 JDK代理类必须要实现InvocationHandler 接口。
调用JDK代理的方法在AspectJAutoProxyCreator类
protected Object createProxy(List<Advice> advices, Object bean) { AopConfigSupport config = new AopConfigSupport(); for (Advice advice : advices) { config.addAdvice(advice); } Set<Class> targetInterfaces = ClassUtils.getAllInterfacesForClassAsSet(bean.getClass()); for (Class<?> targetInterface : targetInterfaces) { config.addInterface(targetInterface); } config.setTargetObject(bean); AopProxyFactory proxyFactory = null; if (config.getProxiedInterfaces().length == 0) { proxyFactory = new CglibProxyFactory(config); } else { //需要实现JDK代理,有接口的情况下 proxyFactory=new JdkAopProxyFactory(config); } return proxyFactory.getProxy(); }