内容简介:回眸一笑百媚生,六宫粉黛无颜色。在前四篇,我们已经实现了使用
回眸一笑百媚生,六宫粉黛无颜色。
概述
在前四篇,我们已经实现了使用 Cglib 实现了 aop 动态代理。但是在 spring 中如果代理对象实现了接口,则默认使用 jdk 动态代理,也可以通过配置强制使用 cglib 代理。本篇,我们使用 jdk 动态代理来完善 aop
准备工作
INioCoderService
新增接口类,因为使用 jdk 动态代理,代理对象必须实现接口。
package com.niocoder.service.v6;
/**
* 测试 JDK 动态代理
*/
public interface INioCoderService {
void placeOrder();
}
NioCoderService
实现 INioCoderService 接口。
@Component(value = "nioCoder")
public class NioCoderService implements INioCoderService {
public NioCoderService() {
}
public void placeOrder() {
System.out.println("place order");
MessageTracker.addMsg("place order");
}
public void placeOrderV2() {
System.out.println("no interception");
}
}
bean-v6.XML
设置 Pointcut 为 v6 包下面的 placeOrder 方法。
<?xml version="1.0" encoding="UTF-8"?>
<!-- 增加namespace-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop">
<!-- 扫描哪个包下面的文件 -->
<context:component-scan base-package="com.niocoder.service.v6">
</context:component-scan>
<!-- 模拟 TransactionManager-->
<bean id="tx" class="com.niocoder.tx.TransactionManager"/>
<!-- aop 配置-->
<aop:config>
<!-- aop 核心配置 依赖tx-->
<aop:aspect ref="tx">
<!-- 切入点配置 包下面的placeOrder 方法-->
<aop:pointcut id="placeOrder"
expression="execution(* com.niocoder.service.v6.*.placeOrder(..))"/>
<!-- 通知配置,-->
<aop:before pointcut-ref="placeOrder" method="start"/>
<aop:after-returning pointcut-ref="placeOrder" method="commit"/>
<aop:after-throwing pointcut-ref="placeOrder" method="rollback"/>
</aop:aspect>
</aop:config>
</beans>
创建jdk代理工厂
根据类图aop 动态获取代理实例 创建 JdkAopProxyFactory 代理工厂。
JdkAopProxyFactory
package com.niocoder.aop.framework;
import com.niocoder.aop.Advice;
import com.niocoder.util.Assert;
import com.niocoder.util.ClassUtils;
import lombok.extern.java.Log;
import org.aopalliance.intercept.MethodInterceptor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
* @author zhenglongfei
*/
@Log
public class JdkAopProxyFactory implements AopProxyFactory, InvocationHandler {
private final AopConfig config;
public JdkAopProxyFactory(AopConfig config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvices().size() == 0) {
throw new AopConfigException("No advices specified");
}
this.config = config;
}
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
public Object getProxy(ClassLoader classLoader) {
log.info("Creating JDK dynamic proxy: target source is " + this.config.getTargetObject());
Class<?>[] proxiedInterfaces = config.getProxiedInterfaces();
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object target = this.config.getTargetObject();
Object retVal;
List<Advice> chain = this.config.getAdvices(method);
if (chain.isEmpty()) {
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();
}
return retVal;
}
}
AspectJAutoProxyCreator
在 AspectJAutoProxyCreator 的 createProxy 方法中添加 JDK 代理支持。
public class AspectJAutoProxyCreator implements BeanPostProcessor {
......
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();
}
......
}
ApplicationContextTest
测试 jdk 动态代理。
public class ApplicationContextTest {
@Before
public void setUp() {
MessageTracker.clearMsgs();
}
@Test
public void testGetBeanProperty() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-v6.xml");
INioCoderService nioCoderService = (INioCoderService) ctx.getBean("nioCoder");
nioCoderService.placeOrder();
List<String> msgs = MessageTracker.getMsgs();
Assert.assertEquals(3, msgs.size());
Assert.assertEquals("start tx", msgs.get(0));
Assert.assertEquals("place order", msgs.get(1));
Assert.assertEquals("commit tx", msgs.get(2));
}
}
输出:
start tx place order commit tx
代码下载
代码下载
参考资料
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
.NET框架程序设计
(美)Jeffrey Richter、(美)Francesco Balena / 李建忠 / 华中科技大学出版社 / 2004-1 / 54.00元
Microsoft.NET框架为简化开发与卫联网无缝连接的应用程序和组件提供了强大的技术支持,如ASP.NET Web窗体、XML Web服务以及Windows窗体。本书的目的在于展示.NET框架中公共语言运行库存的核心内容。全书由两位广受尊敬的开发者/作者完成,并假设读者理解面向对象程序设计的基本概念,如数据抽象、继承和多态。书中内容清楚地解释了CLR的扩展类型系统,CLR如何管理类型的行为,以......一起来看看 《.NET框架程序设计》 这本书的介绍吧!