代理模式是设计模式结构型中的其中一种
实现代理功能有静态代理,动态代理,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();
}