代理模式


(代理模式可以给代理对象额外增加功能操作,扩展对象功能。)

代理的名词

代理对象:增强后的对象 proxy

目标对象:被增强的对象 target

代理的方式

继承:代理对象继承目标对象,重写需要增强的方法;

聚合:目标对象和代理对象实现同一个接口,代理对象当中要包含目标对象。

静态代理

是被代理对象先定义好代理对象,代理对象和目标对象需要实现相同的接口(聚合)或 继承相同的父类

通过聚合方式实现静态代理

代理类:实现xxx接口代理的内容在代理类中写死

// 1.写一个接口
public interface UserDao{
    public void hello();   
}

// 2.写一个接口的实现类
public class UserDaoImpl implements UserDao{
    @Override
    public void hello(){
        System.out.println("Hello");
    }
}

// 3.写一个代理类
public class ProxyUtil implement UserDao{
    private UserDao dao;
    public ProxyUtil(UserDaoImpl dao){
        this.dao = dao;    
    }
    @Override
    public void hello(){
        System.out.println("---before---");  //逻辑增强代码
        impl.hello();  //调用目标对象的方法
    }
} 

// 4.写一个测试类
public Class Test{
    public static void main(){
        UserDao target = new UserDaoImpl();
        ProxyUtil pu = new ProxyUtil(target);
        pu.hello();
    }  
}

通过继承方式实现静态代理

代理类:继承目标类,并重写目标方法实现增强

// 1.写一个目标类
public class UserDaoImpl {
    public void hello(){
        System.out.println("Hello");
    }
}

// 2.写一个代理类继承目标类
public class LogUserDaoImpl extends UserDaoImpl{
    @Override
    public void hello{
        System.out.println("---log---");
        super.hello();
    }
}

// 3.写一个测试类
public class Test{
    public static void main(Stirng[] args){
        UserDaoImpl u = new LogUserDaoImpl();
        u.hello();
    }
}

静态代理存在问题

1.如果需要多个增强功能,则原始类需要层层嵌套实现代理,使代理类过多产生类爆炸。例如A目标类,需要实现Log、Times、Power等功能增强,如果用静态代理继承,则需要先让Log继承A类生成LA代理,再让Times继承LA类生成TLA类代理,再让Power继承TLA类生成PTLA类代理,如果三个顺序调换,还需要重新写继承,使类过多产生爆炸。

动态代理原理

如下类需要动态生成

*如自己模拟一个动态代理

不需要手动创建类文件(因为一旦手动创建类文件,就会产生类爆炸),通过接口反射生成一个类文件,然后调用第三方的编译技术,动态编译这个产生的类文件成class文件,继而利用UrlclassLoader(因为这个动态产生的class不在工程当中所以需要使用UrlclassLoader)把这个动态编译的类加载到jvm当中,最后通过反射把这个类实例化。

即:通过对目标对象的反射生成.java->编译成.class->加载到jvm(处理byte[])->产生类Object

实际动态代理源码

不用生成.java文件和.class文件,通过目标对象的反射生成bytep[],加载到jvm(处理byte[])->产生类Object

JDK代理 -> 示例 https://blog.csdn.net/qq_32532321/article/details/81874990
1)写一个Dao接口
2)写一个DaoImpl类实现接口
3)创建一个代理类xxProxy实现InvocationHandler接口,重新构造方法xxxProxy(Dao target){this.target = target},重写invoke(Object proxy,Method method,Object[] args)方法{method.invoke(target,args)}

  • Object proxy:用处不大
  • Method method:目标对象中包含的方法
  • Object[] args:目标对象中包含方法的入参

4)完成main方法调用代理,即Proxy.newProxyInstance(xxProxy.getClass().getClassLoader(),Dao.getClass.getInterface,new xxProxy(dao))方法

  • xxProxy.getClass().getClassLoader() :因为代理类动态生成,所以需要重新将代理类加载到jvm,所以需要传个ClassLoad
  • Dao.getClass.getInterface:目标对象下所有方法会被代理
  • xxProxy:继承InvocationHandler接口中,如3)

Cglib代理 -> 示例 https://blog.csdn.net/qq_32532321/article/details/81874990
1)写一个DaoImpl实现类
2)写一个xxProxy代理类实现MethodInterceptor接口,
重写intercept(Object o,Method method,Object[] objects,MethodProxy methodProxy)方法{methodProxy.invokeSuper(o,objects)}
3)完成main方法调用代理,新建Enhancer对象,
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(DaoImpl.class);
enhancer.setCallback(new xxProxy());
DaoImpl daoimpl =(DaoImpl) enhancer.create();

*Aop底层实现使用了JDK代理和CgLib代理。
其中JDK代理必须基于接口,因为JDK代理源码中已经自动继承了Proxy类,Java是单继承所以无法再继承实现类(DaoImpl)
Cglib代理是基于继承