從零開始造Spring09---實現AOP的JDK代理
阿新 • • 發佈:2018-12-20
前言
接上一篇從零開始造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();
}