代理模式
(代理模式可以给代理对象额外增加功能操作,扩展对象功能。)
代理的名词
代理对象:增强后的对象 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代理是基于继承