代理模式
1:代理模式简介
可以把代理简单的理解为中介,为目标对象提供代理对象,由代理对象去控制目标对象的引用。因此可以通过代理对象来扩展目标对象功能而无需更改目标对象。
2:代理模式的主要角色
- ISubject:抽象主题角色,目标对象和代理对象共同实现的接口。
- TargetSubject:目标主题角色,是实现抽象主题接口的类。
- Proxy:代理角色,也是实现抽象主题接口的类,内部含有对目标对象TargetSubject的引用,从而可以操作目标对象或者代理目标对象。同时代理对象也可以在操作目标对象的同时扩展功能。
2:代理模式主要有静态代理和动态代理
2.1静态代理
主要分组合静态代理和继承静态代理
- 组合静态代理 (代理对象存放目标对象引用)
//抽象主题
public interface Subject {
void findLove();
}
//目标对象
public class Son implements Subject {
@Override
public void findLove() {
System.out.println("我没空找女人,让我妈妈代理了");
}
}
//代理对象
public class Mother implements Subject{
private Son son;
public Mother(Son son){
this.son = son;
}
@Override
public void findLove() {
this.son.findLove();
System.out.println("妈妈代理了你的请求帮你找女人");
System.out.println("我要找胸大肤白貌美的");
}
}
- 组合静态代理 (代理对象继承目标对象)
2.2动态代理
- jdk动态代理
//抽象主题角色
public interface Person {
public void findlove();
//扩展新的需求 要会玩
public void play();
}
//目标主题角色
public class Gxx implements Person{
@Override
public void findlove() {
System.out.println("要善良的女生");
}
@Override
public void play() {
System.out.println("找会玩的女生");
}
}
//jdk代理对象
public class JDKMeipo implements InvocationHandler{
//保存被代理对象
private Person tartget;
//获取被代理对象实例
public Object getInstance(Person tartget){
this.tartget=tartget;
Class<?> clazz=tartget.getClass();
//用来生成一个对象,通过字节码重组
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
//假如我换成其他功能,动态代理在这边还要改代码
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是媒婆,我要帮你找对象");
System.out.println("开始物色");
method.invoke(this.tartget,args);
System.out.println("我媒婆找到了");
return null;
}
}
//测试类
public class JDKProxyTest {
public static void main(String[] args) {
Person obj=(Person) new JDKMeipo().getInstance(new Gxx());
obj.play();
//原理-------有兴趣的可以自行研究jdk源码
/*
* 1:拿到被代理对象的引用,并且获取它所有的接口(反射获取)
* 2:通过jdk proxy 类重新生成新的类,同时新的类要实现被代理所有实现的接口
* 3:(动态生成java代码)把新加的业务逻辑方法由一定逻辑调用
* 4:编译新生成的java代码
* 5:再重新加载到jvm中运行
* 以上过程叫做字节码重组
* jdk规范,只要是$开头的一般都是动态生成的,比如代理类,内部类
* */
}
}
- cglib动态代理
//目标对象
public class ZhangS {
public void findLove(){
System.out.println("张三要找白富美");
}
}
//代理对象
public class CglibMeiPo implements MethodInterceptor {
public Object getInstance(Class<?> clazz){
Enhancer enhancer=new Enhancer();
//要把哪个类设置为即将生成的新的父类
enhancer.setSuperclass(clazz);
//由谁来当子类呢,自己来当子类(代理类)
enhancer.setCallback(this);
return enhancer.create();
}
//业务的增强
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我是媒婆,我要帮你找对象");
System.out.println("开始物色");
methodProxy.invokeSuper(o,objects);
System.out.println("我媒婆找到了");
return null;
}
}
//测试类
public class CglibTest {
public static void main(String[] args) {
try {
ZhangS obj =(ZhangS) new CglibMeiPo().getInstance(ZhangS.class);
obj.findLove();
}catch (Exception e){
e.printStackTrace();
}
}
}
3:jdk动态代理和cglib动态代理对比
- jdk的动态代理是基于类实现了接口,cglib是基于类,没有强制要求目标类一定要是实现接口。
- jdk的核心是实现InvocationHandler接口,使用invoke()方法进行面向切面的处理,调用相应的通知。
- cglib的核心是实现MethodInterceptor接口,使用intercept()方法进行面向切面的处理,调用相应的通知。
- 其中cglib中有一个Enhancer类,可以使用他快速的创建一个代理类。