起因:在看架構(gòu)設(shè)計(jì)的時(shí)候零蓉,看到代理模式笤受,回想起來(lái)穷缤,做了這么幾年的java敌蜂,雖然知道代理模式,但是未曾深入了解過(guò)津肛,所以去打算研究一下代理模式章喉。
1 代理模式
代理模式的定義:
由于某些原因需要給某對(duì)象提供一個(gè)代理以控制對(duì)該對(duì)象的訪問(wèn)。
這時(shí)身坐,訪問(wèn)對(duì)象不適合或者不能直接引用目標(biāo)對(duì)象秸脱,代理對(duì)象作為訪問(wèn)對(duì)象和目標(biāo)對(duì)象之間的中介。
2 代理模式 概述
代理模式是java中最常用的設(shè)計(jì)模式之一部蛇,尤其是在spring框架中廣泛應(yīng)用摊唇。
對(duì)于java的代理模式,一般可分為:靜態(tài)代理涯鲁、動(dòng)態(tài)代理巷查、以及CGLIB實(shí)現(xiàn)動(dòng)態(tài)代理。
代理模式的主要優(yōu)點(diǎn)有:
- 代理模式在客戶(hù)端與目標(biāo)對(duì)象之間起到一個(gè)中介作用和保護(hù)目標(biāo)對(duì)象的作用抹腿;
- 代理對(duì)象可以擴(kuò)展目標(biāo)對(duì)象的功能岛请;
- 代理模式能將客戶(hù)端與目標(biāo)對(duì)象分離,在一定程度上降低了系統(tǒng)的耦合度警绩,增加了程序的可擴(kuò)展性
其主要缺點(diǎn)是:
- 代理模式會(huì)造成系統(tǒng)設(shè)計(jì)中類(lèi)的數(shù)量增加
- 在客戶(hù)端和目標(biāo)對(duì)象之間增加一個(gè)代理對(duì)象崇败,會(huì)造成請(qǐng)求處理速度變慢;
- 增加了系統(tǒng)的復(fù)雜度肩祥;
以上缺點(diǎn)可以使用動(dòng)態(tài)代理來(lái)解決
3 代理模式 模式結(jié)構(gòu)
代理模式的主要角色如下:
- 抽象主題(Subject)類(lèi):通過(guò)接口或抽象類(lèi)聲明真實(shí)主題和代理對(duì)象實(shí)現(xiàn)的業(yè)務(wù)方法后室。
- 真實(shí)主題(Real Subject)類(lèi):實(shí)現(xiàn)了抽象主題中的具體業(yè)務(wù),是代理對(duì)象所代表的真實(shí)對(duì)象混狠,是最終要引用的對(duì)象岸霹。
- 代理(Proxy)類(lèi):提供了與真實(shí)主題相同的接口,其內(nèi)部含有對(duì)真實(shí)主題的引用檀蹋,它可以訪問(wèn)松申、控制或擴(kuò)展真實(shí)主題的功能。
4 靜態(tài)代理 代碼實(shí)現(xiàn)
package com.test.proxy;
public interface Target {
public String execute();
}
package com.test.proxy;
public class TargetImpl implements Target {
@Override
public String execute() {
System.out.println("TargetImpl execute俯逾!");
return "execute";
}
}
package com.test.proxy;
public class Proxy implements Target{
private Target target;
public Proxy(Target target) {
this.target = target;
}
@Override
public String execute() {
System.out.println("perProcess");
String result = this.target.execute();
System.out.println("postProcess");
return result;
}
}
package com.test.proxy;
public class ProxyTest {
public static void main(String[] args) {
Target target = new TargetImpl();
Proxy p = new Proxy(target);
String result = p.execute();
System.out.println(result);
}
}
總結(jié):由我們創(chuàng)建代理類(lèi)或特定工具自動(dòng)生成源代碼再對(duì)其編譯贸桶,在程序運(yùn)行前代理類(lèi)的 .class 文件就已經(jīng)存在了。
5 動(dòng)態(tài)代理 代碼實(shí)現(xiàn)
package com.agency.staticproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class App {
public static void main(String[] args) {
// 目標(biāo)對(duì)象
// IUserDao target = new UserDao();
MemberServiceImpl target = new MemberServiceImpl();
// 【原始的類(lèi)型 class cn.itcast.b_dynamic.UserDao】
System.out.println(target.getClass());
// 給目標(biāo)對(duì)象桌肴,創(chuàng)建代理對(duì)象
MemberService memberService = (MemberService) new ProxyFactory(target).getProxyInstance();
// class $Proxy0 內(nèi)存中動(dòng)態(tài)生成的代理對(duì)象
System.out.println(memberService.getClass());
// 執(zhí)行方法 【代理對(duì)象】
memberService.getUserById();
}
}
class ProxyFactory{
//維護(hù)一個(gè)目標(biāo)對(duì)象
private Object target;
public ProxyFactory(Object target){
this.target=target;
}
//給目標(biāo)對(duì)象生成代理對(duì)象
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("12222");
//執(zhí)行目標(biāo)對(duì)象方法
Object returnValue = method.invoke(target, args);
String name = method.getName();
System.out.println("233333");
return returnValue;
}
}
);
}
}
class MemberServiceImpl implements MemberService {
@Override
public void getUserById() {
System.out.println(123);
}
}
interface MemberService {
void getUserById();
}
總結(jié):在程序運(yùn)行時(shí)皇筛,運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。
0.根據(jù)所傳入的參數(shù)生成一個(gè)代理類(lèi)
1.代理類(lèi)實(shí)現(xiàn)了相關(guān)接口坠七,繼承了Proxy水醋,其構(gòu)造函數(shù)是有參構(gòu)造旗笔,傳入一個(gè)InvocationHandler。
2.所以拄踪,其使用代理類(lèi)蝇恶,調(diào)用方法,都會(huì)先調(diào)用InvocationHandler中的invoke方法惶桐,
3.至于要不要調(diào)用代理類(lèi)的方法撮弧,需要看,在invoke中是否調(diào)用了method.invoke(target, args)姚糊。
6 CGLIB代理 代碼實(shí)現(xiàn)
package com.agency.cglib;
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 CglibTest {
public static void main(String[] args) {
System.out.println("***************");
Target target = new Target();
CglibTest test = new CglibTest();
Target proxyTarget = (Target) test.createProxy(Target.class);
String res = proxyTarget.execute();
System.out.println(res);
}
public Object createProxy(Class targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MyMethodInterceptor());
return enhancer.create();
}
}
class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(">>>>MethodInterceptor start...");
Object result = proxy.invokeSuper(obj,args);
System.out.println(">>>>MethodInterceptor ending...");
return "result";
}
}
class Target {
public String execute() {
String message = "-----------test------------";
System.out.println(message);
return message;
}
}
總結(jié):CGLib采用了非常底層的字節(jié)碼技術(shù)贿衍,其原理是通過(guò)字節(jié)碼技術(shù)為一個(gè)類(lèi)創(chuàng)建子類(lèi),
并在子類(lèi)中采用方法攔截的技術(shù)攔截所有父類(lèi)方法的調(diào)用救恨,
順勢(shì)織入橫切邏輯贸辈。JDK動(dòng)態(tài)代理與CGLib動(dòng)態(tài)代理均是實(shí)現(xiàn)Spring AOP的基礎(chǔ)。
不要以為每天把功能完成了就行了肠槽,這種思想是要不得的擎淤,互勉~!