一、动态代理技术
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理,利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理,覆盖其中的方法(继承)
1. JDK动态代理
定义一个接口及其实现类
public interface UserService {
void add();
}
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("--------add--------");
}
}
实现JDK提供的InvocationHandler
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------before------");
Object result = method.invoke(target, args);
System.out.println("------after------");
return result;
}
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(), this);
}
}
测试代码:
@Test
public void proxyTest() {
UserService userService = new UserServiceImpl();
MyInvocationHandler handler = new MyInvocationHandler(userService);
UserService proxy = (UserService) handler.getProxy();
proxy.add();
}
输出
------before------
--------add--------
------after------
2. CGLib动态代理
例子如下:
public class EnhancerDemo {
public static void main(String... args){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(EnhancerDemo.class);
enhancer.setCallback(new MethodInterceptorImpl());
EnhancerDemo proxy = (EnhancerDemo) enhancer.create();
proxy.test();
System.out.println(proxy);
}
public void test(){
System.out.println("hello world");
}
static class MethodInterceptorImpl implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
System.out.println("----before invoke"+method);
Object result = methodProxy.invokeSuper(o, args);
System.out.println("****after invoke"+method);
return result;
}
}
}
输出:
----before invoke public void com.season.aop.EnhancerDemo.test()
hello world
****after invoke public void com.season.aop.EnhancerDemo.test()
----before invoke public java.lang.String java.lang.Object.toString()
----before invoke public native int java.lang.Object.hashCode()
****after invoke public native int java.lang.Object.hashCode()
****after invoke public java.lang.String java.lang.Object.toString()
com.season.aop.EnhancerDemo$$EnhancerByCGLIB$$b010a475@18e6db6
public interface Monitorable {
void setMonitorActive(boolean active);
}
建一个类实现该接口并继承DelegatingIntroductionInterceptor
public class MonitorInterceptor extends DelegatingIntroductionInterceptor implements Monitorable {
ThreadLocal<Boolean> active = new ThreadLocal<>();
@Override
public void setMonitorActive(boolean active) {
this.active.set(active);
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object result;
if (active.get() != null && active.get()) {
System.out.println("开始计时");
long start = System.currentTimeMillis();
result = super.invoke(mi);
System.out.println("计时结束,耗时:"+(System.currentTimeMillis()-start)+"ms");
} else
result = super.invoke(mi);
return result;
}
}
这个类做的事情是,当active中的值为true时会在调用方法的时候进行计时统计
再建一个类模拟操作
public class MonitorService {
public void run(){
try {
System.out.println("执行MonitorService - run方法");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在配置文件beans.xml中加上配置
<bean id="monitorService" class="com.season.aop.MonitorService"/>
<bean id="pMonitor" class="com.season.aop.MonitorInterceptor"/>
<bean id="myTestBeanProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
p:interceptorNames="pMonitor"
p:proxyTargetClass="true"
p:target-ref="monitorService"
p:interfaces="com.season.aop.Monitorable"
/>
由于只能通过为目标类创建子类的方式生成引介增强的代理,所以必须把proxyTargetClass设置为true
测试代码
@Test
public void introduceInterceptorTest() {
ApplicationContext actx = new ClassPathXmlApplicationContext("beans.xml");
MonitorService bean = (MonitorService) actx.getBean("myTestBeanProxy");
bean.run();
((Monitorable)bean).setMonitorActive(true);
bean.run();
}
输出:
执行MonitorService - run方法
开始计时
执行MonitorService - run方法
计时结束,耗时:2000ms
三、定义一个切面
@Aspect
public class MyAspect {
@Pointcut(value = "execution(* *.test(..))")
public void test(){}
@Before("test()")
public void beforeTest(){
System.out.println("test before");
}
@After("test()")
public void afterTest(){
System.out.println("test after");
}
}
在beans.xml文件中加上
<aop:aspectj-autoproxy/>
<bean id="myAspect" class="com.season.MyAspect"/>
测试代码
@Test
public void aspectTest() {
ApplicationContext actx = new ClassPathXmlApplicationContext("beans.xml");
MyTestBean bean = (MyTestBean) actx.getBean("myTestBean");
bean.test();
}
输出:
test before
Hello world
test after