1 概念
代理:proxy 結構性模式中的代理模式
要調用目標對象的功能時:不是直接訪問目標對象 而是通過代理對象 間接訪問目標對象的功能:
對目標對象的功能進行擴展
代理對象:對目標對象的功能進行改進和加功
目標對象:功能被擴展的對象
2 靜態代理
要求:
靜態代理:為目標對象創建一個代理類:代理類需要關聯目標對象 代理類和目標對象實現相同的接口/繼承相同的父類
在代理類方法中調用目標對象的方法 在調用之前和之后可以加擴展的代碼
目標對象和代理類 必須實現相同的接口或者相同的父類
准備
public interface WorkerInterface {
void work();
void smoke(String smokeLogo);
void sleep();
}
public class Worker implements WorkerInterface {
private String wname;
public Worker(String wname) {
this.wname = wname;
}
public void work(){
System.out.println("工人:"+wname+",開始工作了!");
}
public void smoke(String smokeLogo){
System.out.println("工人:"+wname+",正在吸煙,煙的牌子是"+smokeLogo+"!");
}
public void sleep(){
System.out.println("工人:"+wname+",正在休息!");
}
@Override
public String toString() {
return "Worker [wname=" + wname + "]";
}
}
package proxy;
public class Proxy {
public static void main(String[] args) {
// 4 創建目標對象
Worker worker = new Worker("張三");
// 5 創建代理對象 並關聯目標
WorkerProxy wp = new WorkerProxy(worker);
// 6 調用代理對象的方法
wp.sleep();
wp.work();
wp.smoke("中華");
}
}
// 1 實現相同接口
class WorkerProxy implements WorkerInterface {
// 2 關聯目標對象
private WorkerInterface worker;
public WorkerProxy(WorkerInterface worker) {
this.worker = worker;
}
// 3 在代理對象的方法中 調用目標對象的方法 在調用之前和之后可以加擴展的代碼
@Override
public void work() {
worker.work();
System.out.println(worker + "辛苦了!");
System.out.println("*************************************");
}
@Override
public void smoke(String smokeLogo) {
System.out.println(worker + "吸煙有害健康!");
worker.smoke(smokeLogo);
System.out.println("*************************************");
}
@Override
public void sleep() {
System.out.println(worker + "勞逸結合!");
worker.sleep();
System.out.println(worker + "睡覺結束,滿血復活!");
System.out.println("*************************************");
}
}
總結
優點:可以實現對目標對象功能的擴展
缺點:1 只能代理指定接口的實現類
2 不能對目標對象的特有功能進行擴展
3 動態代理(jdk代理)
概念
*動態代理:
* 1.不需要聲明定義一個代理類
* 2.代理對象的生成,是利用JDK的API,動態的在內存中構建代理對象(需要我們指定創建代理對象/目標對象實現的接口的類型)
* 3.動態代理也叫做:JDK代理
*
*通過java.lang.reflect. Proxy 的newProxyInstance方法在內存中動態生成目標對象的代理對象
*** 動物類 ***
package proxy;
public class Cat implements Animal{
public void eat(){
System.out.println("貓愛吃魚!");
}
}
interface Animal{
void eat();
}
代理對象的工廠類:寫法1:普通寫法
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyF {
public static void main(String[] args) {
// 創建目標對象
Worker w = new Worker("林風");
// 創建工廠對象
ProxyFactory factroy = new ProxyFactory(w);
// 通過工廠對象動態獲取一個代理對象
WorkerInterface wi = (WorkerInterface) factroy.getProxy();
wi.sleep();
wi.work();
wi.smoke("芙蓉王");
//創建工廠對象
ProxyFactory factroy2=new ProxyFactory(new Cat());
Animal a=(Animal)factroy2.getProxy();
a.eat();
}
}
// 1 定義一個代理類工廠對象:實現接口InvocationHandler
class ProxyFactory implements InvocationHandler {
// 2 定義引用記錄目標對象:通過構造方法關聯
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 3 定義方法: 通過Proxy的newProxyInstance方法動態的在內存中創建目標對象的代理對象
public Object getProxy() {
/**
* newProxyInstance三個參數
* 1 loader: 用哪個類加載器去加載代理對象
* 2 interfaces:動態代理類需要實現的接口
* 3 h:動態代理方法在執行時,會調用h里面的invoke方法去執行
**/
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
// 4 實現InvocationHandler的invoke方法:目標對象的每個方法被調用:此invoke方法發都會被調用一次
/**
* invoke三個參數
* 1 proxy:就是代理對象,newProxyInstance方法的返回對象
* 2 method:調用的方法
* 3 args:方法中的參數
**/
@Override
public Object invoke(Object obj, Method method, Object[] params) throws Throwable {
System.out.println(method + ":" + params + ":::方法執行前的擴展");
Object result = null;
result = method.invoke(target, params);
System.out.println(method + ":" + params + ":::方法執行后的擴展");
System.out.println("*******************************************");
return result;
}
}
代理對象的工廠類:寫法2:匿名內部類來實現
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyF {
public static void main(String[] args) {
// 創建目標對象
Worker w = new Worker("林風");
// 創建工廠對象
ProxyFactory factroy = new ProxyFactory(w);
// 通過工廠對象動態獲取一個代理對象
WorkerInterface wi = (WorkerInterface) factroy.getProxy();
wi.sleep();
wi.work();
wi.smoke("芙蓉王");
// 創建工廠對象
ProxyFactory factroy2 = new ProxyFactory(new Cat());
Animal a = (Animal) factroy2.getProxy();
a.eat();
}
}
class ProxyFactory {
// 定義引用記錄目標對象:通過構造方法關聯
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 定義方法: 通過Proxy的newProxyInstance方法動態的在內存中創建目標對象的代理對象
public Object getProxy() {
/**
* newProxyInstance三個參數
* 1 loader: 用哪個類加載器去加載代理對象
* 2 interfaces:動態代理類需要實現的接口
* 3 h:動態代理方法在執行時,會調用h里面的invoke方法去執行
**/
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
/**
* invoke三個參數
* 1 proxy:就是代理對象,newProxyInstance方法的返回對象
* 2 method:調用的方法
* 3 args:方法中的參數
**/
// 實現InvocationHandler的invoke方法:目標對象的每個方法被調用:此invoke方法發都會被調用一次
@Override
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
System.out.println(method + ":" + params + ":::方法執行前的擴展");
Object result = null;
result = method.invoke(target, params);
System.out.println(method + ":" + params + ":::方法執行后的擴展");
System.out.println("************************************************************");
return result;
}
});
}
}
總結
jdk代理:可以代理任意目標對象:但目標類必須實現接口
4 cglib代理
概念
* CGLIB代理:子類對象
* 在運行時期,在內存中動態的創建一個目標對象類的子類對象
* 被spring框架的aop使用:依賴的jar被融入到了spring-core的jar
* 先導入jar: spring-core-3.2.18.RELEASE.jar
* 優點:可以為所有對象動態創建代理對象::不需要目標對象實現接口
目標對象類
class Book{
public int add(int a,int b){
System.out.println(a+"+"+b+"="+(a+b));
return a+b;
}
}
代理工廠類
package proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class ProxyF {
public static void main(String[] args) {
// 創建目標對象
Book b = new Book();
// 創建工廠對象
ProxyFactory factroy = new ProxyFactory(b);
// 通過工廠對象動態獲取一個代理對象
Book bproxy = (Book) factroy.getProxy();
// 調用代理對象的方法;
System.out.println(bproxy.add(1, 2));
}
}
// 1 創建代理工廠類 實現接口MethedInterceptor
class ProxyFactory implements MethodInterceptor {
// 2 關聯目標對象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 3 創建方法獲取代理對象
public Object getProxy() {
// 1 創建工具類
Enhancer eh = new Enhancer();
// 2 指定父類
eh.setSuperclass(target.getClass());
// 3 設置回調函數
eh.setCallback(this);
// 4 獲取代理對象
return eh.create();
}
/**
* intercept四個參數
* 1 Object o:代理對象本身
* 2 Method method: 被代理對象的方法
* 3 Object[] objects:函數調用的參數
* 4 MethodProxy methodProxy:方法的代理
**/
// 4 實現intercep方法:目標對象的方法每次被調用 此方法都會被調用
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println("cglib代理:::方法執行前的擴展代碼");
Object result = null;
result = arg1.invoke(target, arg2);
System.out.println("cglib代理:::方法執行后的擴展代碼");
return result;
}
}
總結
cglib代理:不需要目標類 實現接口