代理的理解
代理(Proxy)是一種設計模式,提供了對目標對象另一種訪問方式;即通過代理對象訪問目標對象.這樣做的好處是:可以在實現目標對象功能的基礎上,增強額外的功能操作,即擴展目標對象的功能。
代理的分類:1、靜態代理 2、動態代理 3、Cjlib代理
靜態代理
由程序員創建或由特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了
需要定義接口或者父類,被代理對象與代理對象一起實現相同的接口或者是繼承相同父類
接口
package com.linewell.staticproxy;
public interface IUserDao{
public void save();
}
目標對象
package com.linewell.staticproxy;
public class UserDao implements IUserDao{
@Override
public void save() {
System.out.println("我是目標對象保存的方法");
}
}
代理對象
package com.linewell.staticproxy;
public class UserDaoProxy implements IUserDao {
//接收保存目標對象
private IUserDao iUserDao;
public UserDaoProxy(IUserDao iUserDao){
this.iUserDao=iUserDao;
}
@Override
public void save() {
System.out.println("開始事物。。。。");
iUserDao.save();
System.out.println("執行事物。。。。");
}
}
測試類
package com.linewell.staticproxy;
public class App {
public static void main(String[] args) {
//創建目標對象
UserDao userDao=new UserDao();
//把目標對象傳給代理對象
UserDaoProxy userDaoProxy=new UserDaoProxy(userDao);
userDaoProxy.save();
}
}
優點:在不改變目標對象的前提下,對目標對象進行擴展。
缺點:目標對象和代理對象都要實現相同的接口,如果說沒有接口,那麼就無法使用靜態代理。
動態代理
也叫jdk代理,接口代理,代理對象不需要實現接口,代理的對象的生成是利用jdk的API通過反射的機制動態生成的。
反射:反射機制在運行狀態中,對於任何一個類,可以知道他的所有屬性和方法,對於任何一個對象,可以調用他的任意一個方法與屬性
代理類:
package com.linewell.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory implements InvocationHandler{
//定義一個目標對象
private Object target;
//給目標對象創建代理對象
public ProxyFactory(Object target) {
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------------------before------------------");
Object returnValue= method.invoke(target, args);
System.out.println("------------------after------------------");
return returnValue;
}
//創建獲取代理的方法
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
測試類:
package com.linewell.dynamicproxy;
import com.linewell.staticproxy.IUserDao;
import com.linewell.staticproxy.UserDao;
public class App {
public static void main(String[] args) {
//創建目標對象
IUserDao iUserDao=new UserDao();
System.out.println(iUserDao.getClass());
iUserDao.save();
//給目標對象創建代理對象
IUserDao proxy =(IUserDao)new ProxyFactory(iUserDao).getProxyInstance();
System.out.println(proxy.getClass());
proxy.save();
}
}
總結:代理對象不需要實現接口,但是目標對象一定要實現接口,否則不能用動態代理。
Cjlib代理
上面的靜態代理和動態代理模式都是要求目標對象是實現一個接口的目標對象,但是有時候目標對象只是一個單獨的對象,並沒有實現任何的接口,這個時候就可以使用以目標對象子類的方式類實現代理,這種方法就叫做:Cglib代理,Cglib代理,也叫作子類代理,它是在內存中構建一個子類對象從而實現對目標對象功能的擴展.
原理是通過字節碼技術爲一個類創建子類,並在子類中採用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。,但因爲採用的是繼承,所以不能對final修飾的類進行代理。
目標類:
package com.linewell.cjlib;
public class Cat {
public void eat(){
System.out.println("貓會釣魚。。。。");
}
public void run(){
System.out.println("貓會上樹。。。。");
}
}
代理類:
package com.linewell.cjlib;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CatProxy implements MethodInterceptor{
//在內存中創建一個全新的類 沒有類型 Enhancer類是CGLib中的一個字節碼增強器
private Enhancer enhancer = new Enhancer();
//創建代理對象的方法
public Object createProxyObject(Class clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通過字節碼技術動態創建子類實例
Object o=enhancer.create();
return o;
}
//intercept()方法攔截所有目標類方法的調用
//o表示目標類的實例
//method爲目標類方法的反射對象
//MethodProxy爲生成的代理類對方法的代理引用。
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
Object obj = proxy.invokeSuper(o, args);//調用類目標類方法
System.out.println("後置代理");
return obj;
}
}
測試類:
package com.linewell.cjlib;
public class App {
public static void main(String[] args) {
CatProxy catProxy = new CatProxy();
Cat cat = new Cat();
cat =(Cat) catProxy.createProxyObject(cat.getClass());
cat.eat();
}
}