代理模式是設計模式結構型中的其中一種
實現代理功能有靜態代理,動態代理,Cglib的幾種方式
如果沒有概念,接下來一一分別代碼簡單實現,看看主要的不同,寫完基本能有個基本認知
代理即 兩個類之間不直接產生關係,而由中間設置的代理類來實現交互。
先做一個例子
1.單純恰飯
學生吃飯,(沒得辦法只會來這些吃飯簡單例子)
老師吃飯。
分別實現Person接口
Person:
public interface Person {
void eat();
}
Student:
public class Student implements Person{
@Override
public void eat() {
System.out.println("Student eating");
}
}
Teacher:
public class Teacher implements Person{
@Override
public void eat() {
System.out.println("Teachers eating");
}
}
2.吃飯前運動一下,吃飯後讀一下書
Student:
public class Student implements Person{
@Override
public void eat() {
System.out.println("play basketball");
System.out.println("Student eating");
System.out.println("read 《五年高考三年模擬》");
}
}
Teacher:
public class Teacher implements Person{
@Override
public void eat() {
System.out.println("play basketball");
System.out.println("Teachers eating");
System.out.println("read 《五年高考三年模擬》");
}
}
當然老視也得看五三
那這樣的話我們沒增加一個功能的話都必須老視學生一起改,很繁瑣,七八個十幾個person實現類、
有沒有簡單的一勞永逸的簡單三五行實現的呢,這個還真的有
那就是 代理了,
先說一個 靜態代理
一、靜態代理
靜態代理必須要實現 統一的接口,重寫方法,所不同的是傳入不同的實現類,就會不同的實現,
最後如果再對 吃前後進行增強減弱都可以在代理類中進行更改,student和teacher都不需要再動了
ProxyPerson:
public class ProxyPerson implements Person{
private Person person = null;
public ProxyPerson(Person person1) {
person = person1;
}
@Override
void eatting() {
System.out.println("washing clothes before eating");
person.eat();
System.out.println("run after eated");
}
}
測試:
/**
* 靜態代理
* 實現學生和老師的池
* 改變代理類的同時不影響原生類
*/
@Test
public void smain() {
ProxyPerson proxyPerson = new ProxyPerson(new Student());
ProxyPerson proxyPerson2 = new ProxyPerson(new Teacher());
proxyPerson.eatting();
System.out.println("-------->>");
proxyPerson2.eatting();
}
二、動態代理
動態代理是jdk 自帶的包,不需要額外導入
動態代理的必要條件是必須要實現相同的接口。
基本的實現就是通過反射得到 代理實現,將參數傳入,invoke執行即可
動態代理需要實現 InvocationHandler 接口,重寫 invoke() 方法
public class JDKProxyHandler implements InvocationHandler {
private Object obj;
public JDKProxyHandler(Object resut) {
this.obj = resut;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("wash clothes before eat----");
Object result = method.invoke(obj, args);
System.out.println("run after ea8888t");
return result;
}
/**
* 獲取代理 類對象
*
* @param <T>
* @return
*/
public <T> T getObj() {
return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
}
測試方法
/**
* JDK 自帶的動態代理 必須實現接口
* 主要是反射method.invoke()
*/
@Test
public void getProxy() {
JDKProxyHandler studentP = new JDKProxyHandler(new Student());
JDKProxyHandler teacherP = new JDKProxyHandler(new Teacher());
Person s = studentP.getObj();
Person t = teacherP.getObj();
s.eat();
System.out.println("------------========》》》");
t.eat();
}
三、Cglib 織入
JDK 的動態代理需要 實現相同的接口,有一定的侷限性。
而爲了應對這個問題,出現了新技術Cglib
CGLib(Code Generator Library)是一個強大的、高性能的代碼生成庫。底層使用了ASM(一個短小精悍的字節碼操作框架)來操作字節碼生成新的類。
而需要使用需要額外導入三方的jar
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
實現 MethodInterceptor 接口具體的代碼
public class CglibClass implements MethodInterceptor {
// 單例模式獲取實例
private static CglibClass cglibClass = new CglibClass();
public static CglibClass getInstance() {
return cglibClass;
}
// 獲取被代理的目標類
public <T> T getProxy(Class<T> clazz) {
return (T) Enhancer.create(clazz, this);
}
/**
* 代理執行目標類方法
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("read before eated");
Object invoke = methodProxy.invokeSuper(o, objects);
System.out.println("run after eated");
return invoke;
}
測試方法
/**
* cglib 代理目標類,並且在類中進行自定義增強
*/
@Test
public void getProxyIn() {
Person proxy = CglibClass.getInstance().getProxy(Student.class);
Person proxy2 = CglibClass.getInstance().getProxy(Teacher.class);
proxy.eat();
System.out.println("-=-=-=-=-=--=--=--=->>");
proxy2.eat();
}