一、動態代理技術
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