靜態代理、動態代理
阿新 • • 發佈:2018-07-03
== getclass 切面 接口 tor 7月 第一個 proxy 字節碼
代理模式最大的優勢就是能夠解耦,在spring中也是廣泛使用。spring中一個重要的特性就是aop,aop是個啥東西呢?其實很簡單,比如現在有個業務方法,那這個業務方法很重要,涉及到非常重要的業務數據,那對於廣大企業應用來說,為了以後能夠及時的定位問題,需要記錄相關入參以及出參到日誌表。
但是對於企業應用來說,需要記錄日誌的地方應該是蠻多的,如果每個方法中都手動的去寫這些記錄日誌的東西,就會特別的冗余,那使用代理模式就可以解決。
一、靜態代理
1、User接口
package com.ty.staticProxy;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下沒有難敲的代碼!
*/
public interface User {
/*
* 業務邏輯接口
*/
public void work(String workName);
}
2、UserImpl實現類
package com.ty.staticProxy;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下沒有難敲的代碼!
*/
public class UserImpl implements User {
/*
* 實際業務邏輯實現方法
*/
@Override
public void work(String workName) {
System.out.println("我是做" + workName + "的");
}
}
3、代理類
package com.ty.staticProxy;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下沒有難敲的代碼!
* 此類為代理類,並且實現業務邏輯類接口,接收一個實際業務處理對象
*/
public class ProxyUser implements User {
private User user;
public ProxyUser(User user) {
this.user = user;
}
@Override
public void work(String workName) {
/*
* 調用實際業務邏輯處理前可以定制化一些功能
*/
System.out.println("工作前先放松放松=============");
/*
* 調用實際業務邏輯處理方法
*/
user.work(workName);
/*
* 調用實際業務邏輯處理後也可以定制一些功能
*/
System.out.println("工作後還是要放松放松=============");
}
}
4、StaticProxyDemo
package com.ty.staticProxy;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下沒有難敲的代碼!
*/
public class StaticProxyDemo {
public static void main(String[] args) {
User proxyUser = new ProxyUser(new UserImpl());
proxyUser.work("java開發");
}
}
運行結果:
工作前先放松放松=============
我是做java開發的
工作後還是要放松放松=============
二、動態代理
在java中,實現動態代理主要有兩種方式,一種是jdk動態代理,一種是cglib
1、jdk動態代理
User以及UserImpl跟上面一致
a、UserDynamicProxy
package com.ty.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author Taoyong
* @date 2018年7月2日
* 天下沒有難敲的代碼!
*/
public class UserDynamicProxy implements InvocationHandler {
private User user;
public UserDynamicProxy(User user) {
this.user = user;
}
/*
* jdk動態代理基於接口,其中proxy好像沒啥卵用、method代表當前被代理對象的實際調用方法、args則代表方法參數
* 由invoke方法對被代理對象進行相關的增強
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("工作前放松放松========");
method.invoke(user, args);
System.out.println("工作後也要放松放松===========");
return null;
}
}
b、DynamicProxyDemo
package com.ty.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* @author Taoyong
* @date 2018年7月2日
* 天下沒有難敲的代碼!
*/
public class DynamicProxyDemo {
public static void main(String[] args) {
User user = new UserImpl();
InvocationHandler h = new UserDynamicProxy(user);
/*
* 使用Proxy的靜態方法是生成代理類的核心。
* 一共有三個參數:
* 1、第一個參數是被代理類的類加載器,通過此類加載器將代理類加載入jvm中;
* 2、第二個參數則是被代理類所實現的所有接口,需要所有的接口的目的是創建新的代理類實現被代理類的所有接口,保證被代理類所有方法都能夠
* 被代理。其實代理的核心就是新創建一個類並實例化對象,去集成被代理對象所有功能的同時,再加入某些特性化的功能;
* 3、第三個參數則是真正的擴展,使用動態代理的主要目的就是能夠對原方法進行擴展,尤其是對於大部分方法都具有的重復方法(例如記錄日誌),
* 可以理解為面向切面編程中的增強.
*/
User proxy = (User) Proxy.newProxyInstance(User.class.getClassLoader(), user.getClass().getInterfaces(), h);
/*
* 在調用生成的代理類對象後,調用原方法後,該method對象以及參數等會被傳入到InvocationHandler的invoke方法中,由InvocationHandler的
* invoke方法對被代理類對象進行增強。
*/
proxy.work("敲代碼");
proxy.eat("吃大餐");
}
}
2、cglib代理
jdk動態代理的缺點就是必須基於接口,沒有接口就無法實現代理,而cglib則是使用繼承的方式去生成代理類,使用範圍更廣
a、添加cglib.jar、asm.jar(註意jar包版本)
使用cglib前必須進行導包,並且版本如果過低會導致報錯
b、UserImpl(使不使用接口都可以)
package com.ty.dynamic.cglib;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下沒有難敲的代碼!
*/
public class UserImpl {
/*
* 實際業務邏輯實現方法
*/
public void work(String workName) {
System.out.println("我是做" + workName + "的");
}
}
c、CglibDynamicProxy
package com.ty.dynamic.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* @author Taoyong
* @date 2018年7月2日
* 天下沒有難敲的代碼!
*/
public class CglibDynamicProxy implements MethodInterceptor {
/*
* 實際的增強
*/
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("這是前處理==============");
methodProxy.invokeSuper(obj, objects);
System.out.println("這是前處理==============");
return null;
}
}
d、CglibProxyDemo
package com.ty.dynamic.cglib;
import net.sf.cglib.proxy.Enhancer;
/**
* @author Taoyong
* @date 2018年7月2日
* 天下沒有難敲的代碼!
*/
public class CglibProxyDemo {
public static void main(String[] args) {
/*
* 創建字節碼增強器
*/
Enhancer enhancer = new Enhancer();
/*
* 被代理類設置為字節碼增強器父類,cglib使用的是繼承方式去創建代理類
*/
enhancer.setSuperclass(UserImpl.class);
/*
* 設置字節碼增強器回調方法
*/
enhancer.setCallback(new CglibDynamicProxy());
/*
* 創建代理實例
*/
UserImpl userImpl = (UserImpl) enhancer.create();
userImpl.work("敲代碼");
}
}
靜態代理、動態代理