3.1. 代理模式
3.1.1. 靜態(tài)代理
靜態(tài)代理角色分析
抽象角色 : 一般使用接口或者抽象類來實(shí)現(xiàn)
真實(shí)角色 : 被代理的角色
代理角色 : 代理真實(shí)角色 ; 代理真實(shí)角色后 , 一般會做一些附屬的操作 .
客戶 : 使用代理角色來進(jìn)行一些操作 .
舉個實(shí)際中的例子:租客通過房產(chǎn)中介進(jìn)行租房的活動疚脐。對應(yīng)到上面的角色分析,租房行為對應(yīng)抽象角色代态,真實(shí)角色對應(yīng)房東蟀俊,代理角色對應(yīng)中介鸵贬,租客對應(yīng)客戶嘀趟。
public interface Rent {
void rent();
}
?
public class Host implements Rent{
@Override
public void rent() {
System.out.println("I hava a room to rent");
}
}
?
public class RentProxy implements Rent{
private Host host;
?
public RentProxy() {
}
?
public RentProxy(Host host) {
this.host = host;
}
?
@Override
public void rent() {
host.rent();
sign();
}
?
// 代理類的附加行為
public void sign(){
System.out.println("I can sign a contract");
}
}
?
public class consumer {
public static void main(String[] args) {
RentProxy rentProxy = new RentProxy(new Host());
rentProxy.rent();
}
}
優(yōu)點(diǎn):可以對已有的功能進(jìn)行增強(qiáng)而不用對已有代碼進(jìn)行改動
缺點(diǎn):增大代碼量嚷狞,每一個需要代理的類都必須要用一個代理類
結(jié)合上如問題雄驹,引申出動態(tài)代理的實(shí)現(xiàn)方法。
3.1.2. 動態(tài)代理
動態(tài)代理的角色和靜態(tài)代理的一樣 .
動態(tài)代理的代理類是動態(tài)生成的 . 靜態(tài)代理的代理類是我們提前寫好的
-
動態(tài)代理分為兩類 : 一類是基于接口動態(tài)代理 , 一類是基于類的動態(tài)代理
基于接口的動態(tài)代理----JDK動態(tài)代理
基于類的動態(tài)代理--cglib
現(xiàn)在用的比較多的是 javasist 來生成動態(tài)代理
3.1.2.1. JDK動態(tài)代理
核心 : InvocationHandler 和 Proxy
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
?
public void setRent(Rent rent) {
this.rent = rent;
}
?
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
?
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(rent, args);
return result;
}
}
一個動態(tài)代理 , 一般代理某一類業(yè)務(wù)
3.1.2.2. CGLIB動態(tài)代理
核心:MethodInterceptor和Enhancer
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("這里是對目標(biāo)類進(jìn)行增強(qiáng)Q痛恰R接摺!");
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
}
public class Client {
public static void main(String[] args) {
//創(chuàng)建Enhancer對象象缀,類似于JDK動態(tài)代理的Proxy類蔬将,下一步就是設(shè)置幾個參數(shù)
Enhancer enhancer = new Enhancer();
//設(shè)置目標(biāo)類的字節(jié)碼文件
enhancer.setSuperclass(Dog.class);
//設(shè)置回調(diào)函數(shù)
enhancer.setCallback(new CglibProxy());
//這里的creat方法就是正式創(chuàng)建代理類
Dog dogProxy = (Dog)enhancer.create();
//調(diào)用代理類的shout方法
dogProxy.shout();
}
}
3.1.3. AOP
AOP(Aspect Oriented Programming)意為:面向切面編程,通過預(yù)編譯方式和運(yùn)行期動態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)央星。
3.1.3.1. 核心概念
橫切關(guān)注點(diǎn):跨越應(yīng)用程序多個模塊的方法或功能霞怀。即是,與我們業(yè)務(wù)邏輯無關(guān)的莉给,但是我們需要關(guān)注的部分毙石,就是橫切關(guān)注點(diǎn)。如日志 , 安全 , 緩存 , 事務(wù)等等 ....
切面(ASPECT):橫切關(guān)注點(diǎn) 被模塊化 的特殊對象颓遏。即徐矩,它是一個類。
通知(Advice):切面必須要完成的工作叁幢。即滤灯,它是類中的一個方法。
目標(biāo)(Target):被通知對象。
代理(Proxy):向目標(biāo)對象應(yīng)用通知之后創(chuàng)建的對象鳞骤。
切入點(diǎn)(PointCut):切面通知執(zhí)行的 “地點(diǎn)”的定義窒百。
連接點(diǎn)(JointPoint):與切入點(diǎn)匹配的執(zhí)行點(diǎn)。
SpringAOP中豫尽,通過Advice定義橫切邏輯篙梢,Spring中支持5種類型的Advice:
3.1.3.2. 案例說明
public interface UserService {
void add();
void delete();
void update();
void select();
}
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("ADD方法執(zhí)行");
}
?
@Override
public void delete() {
System.out.println("DELETE方法執(zhí)行");
}
?
@Override
public void update() {
System.out.println("UPDATE方法執(zhí)行");
}
?
@Override
public void select() {
System.out.println("SELECT方法執(zhí)行");
}
}
// AOP增強(qiáng)類
public class Log implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被執(zhí)行了");
}
}
?
public class Client {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean("userService",UserService.class);
userService.add();
}
}
其他說明:
<aop:aspectj-autoproxy />
有一個proxy-target-class屬性,默認(rèn)為false拂募,表示使用jdk動態(tài)代理織入增強(qiáng)庭猩,當(dāng)配為<aop:aspectj-autoproxy poxy-target-class="true"/>時,表示使用CGLib動態(tài)代理技術(shù)織入增強(qiáng)陈症。不過即使proxy-target-class設(shè)置為false蔼水,如果目標(biāo)類沒有聲明接口,則spring將自動使用CGLib動態(tài)代理录肯。