靜態代理和動態代理
靜態代理:
角色:
1.抽象接口(租房:接口)
2.真實角色(比如房東小張:實現類實現抽象接口)
3.代理角色(代理真實角色,比如中介,負責幫小張賣方:實現類實現抽象接口,同時擁有小張這個成員屬性,它可以調用小張實現的方法,並且增加自己的方法在裏面)
4.客戶(買房人:比如測試類,直接new 真實角色,並把真實角色傳入new 代理角色中)
例子:
//抽象接口:租房
public interface Rent {
public void rent();
}
//真實角色: 房東
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
//代理角色:中介
public class Proxy implements Rent {
private Host host;
public Proxy() { }
public Proxy(Host host) {
this.host = host;
}
//租房
public void rent(){
seeHouse();
host.rent();
fare();
}
//看房
public void seeHouse(){
System.out.println("帶房客看房");
}
//收中介費
public void fare(){
System.out.println("收中介費");
}
}
//客戶類,一般客戶都會去找代理!
public class Client {
public static void main(String[] args) {
//房東要租房
Host host = new Host();
//中介幫助房東
Proxy proxy = new Proxy(host);
//你去找中介!
proxy.rent();
}
}
核心思想:沒有改變房東的代碼,通過構造了新實現類中介,增強了房東的功能。對房東類進行了擴展。
即,我們在不改變原來的代碼的情況下,實現了對原有功能的增強,這是AOP中最核心的思想
動態代理
在靜態代理的例子中,Proxy類把房東小張作爲成員變量,因此它只能代理小張(代碼寫死了)。如果存在其他房東也需要被代理,那對每個房東都需要寫它的代理對象。因此引入動態代理,只需寫一個代理對象,實現所有房東都能被代理。
動態代理分爲兩類 : 一類是基於接口動態代理 , 一類是基於類的動態代理:基於接口的動態代理----JDK動態代理,基於類的動態代理--cglib
兩個關鍵類:InvocationHandler 和 Proxy
實現動態代理的步驟:
新建代理類繼承InvocationHandler(把要代理的抽象接口作爲屬性傳入),重寫invoke方法。對該接口調用靜態類Proxy.newProxyInstance()方法返回代理對象。
//抽象角色:租房
public interface Rent {
public void rent();
}
//真實角色: 房東,房東要出租房子
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
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);
}
// proxy : 代理類 method : 代理類的調用處理程序的方法對象.
// 處理代理實例上的方法調用並返回結果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
seeHouse();
//核心:本質利用反射實現!
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("帶房客看房");
}
//收中介費
public void fare(){
System.out.println("收中介費");
}
}
//租客
public class Client {
public static void main(String[] args) {
//真實角色
Host host = new Host();
//代理實例的調用處理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host); //將真實角色放置進去!
Rent proxy = (Rent)pih.getProxy(); //動態生成對應的代理類!
proxy.rent();
}
}
AOP方面
首先導入依賴
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式1:自己實現增強類(實現spring提供的接口) + xml配置 ——>見ref
方式2:自定義切入類 + xml配置 ——>見ref
方式3:註解
第一步:編寫一個註解實現的增強類
package com.kuang.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法執行前---------");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法執行後---------");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("環繞前");
System.out.println("簽名:"+jp.getSignature());
//執行目標方法proceed
Object proceed = jp.proceed();
System.out.println("環繞後");
System.out.println(proceed);
}
}
第二步:在Spring配置文件中,註冊bean,並增加支持註解的配置
<!--第三種方式:註解實現-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
Reference:
狂神說公衆號:https://www.bilibili.com/video/BV1WE411d7Dv
靜態/動態代理模式:https://mp.weixin.qq.com/s/McxiyucxAQYPSOaJSUCCRQ
AOP就這麼簡單:https://mp.weixin.qq.com/s/zofgBRRrnEf17MiGZN8IJQ