第一種:靜態代理
程式碼實現
1.設計介面
public interface IUserDao {
void save();
}
2.實現介面
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("----已經儲存資料!----");
}
}
3.代理類
必須實現介面
public class UserDaoProxy implements IUserDao {
//接收儲存目標物件
private IUserDao target;
public UserDaoProxy(IUserDao target){
this.target=target;
}
@Override
public void save() {
System.out.println("開始事務...");
target.save();//執行目標物件的方法
System.out.println("提交事務...");
}
}
4.測試類
public class App {
public static void main(String[] args) {
//目標物件
UserDao target = new UserDao();
//代理物件,把目標物件傳給代理物件,建立代理關係
UserDaoProxy proxy = new UserDaoProxy(target);
proxy.save();//執行的是代理的方法
}
}
第二種:JDK動態代理
程式碼實現
1.設計介面
public interface IUserDao {
void save();
}
2.實現介面
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("----已經儲存資料!----");
}
}
3.代理類
不需要實現介面
public class ProxyFactory {
//維護一個目標物件
private Object target;
public ProxyFactory(Object target){
this.target=target;
}
//這是Java8語法
public Object getProxyInstanceLambda(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy,method,args) -> {
System.out.println("開始事務2");
//執行目標物件方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事務2");
return returnValue;
});
}
//傳統語法
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("開始事務2");
//執行目標物件方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事務2");
return returnValue;
}
});
}
}
4.測試類
public class App {
public static void main(String[] args) {
// 目標物件
IUserDao target = new UserDao();
// 【原始的型別 class UserDao】
System.out.println(target.getClass());
// 給目標物件,建立代理物件
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstanceLambda();
// class $Proxy0 記憶體中動態生成的代理物件
System.out.println(proxy.getClass());
// 執行方法 【代理物件】
proxy.save();
}
}
第三種:Cglib代理
程式碼實現
1.目標物件類
public class UserDao {
public void save() {
System.out.println("----已經儲存資料!----");
}
}
2.Cglib代理工廠
public class ProxyFactory implements MethodInterceptor {
//維護目標物件
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//給目標物件建立一個代理物件
public Object getProxyInstance(){
//1.工具類
Enhancer en = new Enhancer();
//2.設定父類
en.setSuperclass(target.getClass());
//3.設定回撥函式
en.setCallback(this);
//4.建立子類(代理物件)
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("開始事務...");
//執行目標物件的方法
Object returnValue = method.invoke(target, objects);
System.out.println("提交事務...");
return returnValue;
}
}
3.測試類
public class App {
public static void main(String[] args) {
//目標物件
UserDao target = new UserDao();
//代理物件
UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();
//執行代理物件的方法
proxy.save();
}
}
三者的區別
1.靜態代理
目標物件要實現介面,而且代理物件需要實現介面。
這樣的代理類只能代理特定介面的物件,靈活度不夠。
2.JDK動態代理
代理物件不需要實現介面,但是目標物件一定要實現介面,否則不能用動態代理
3.CGLib動態代理
代理物件不需要實現介面,目標物件也可以是單純的一個物件。
在Spring的AOP程式設計中:
如果加入容器的目標物件有實現介面,用JDK代理.
如果目標物件沒有實現介面,用Cglib代理.
本作品採用《CC 協議》,轉載必須註明作者和本文連結