开始工作也已经有一年了,最近一直在学习设计模式,现将所学记录一下,方便日后查阅。
我近期学习的设计模式是代理模式,所以先写这个。
代理模式介绍:
代理模式有静态代理、动态代理(其中动态代理有jdk动态代理和cglib动态代理)。
定义:
提供一个对象来对目标对象进行代理,用代理对象来替代目标对象从而达到对目标对象的控制和隐藏。
为什么使用代理模式:
开闭原则:使用代理模式生成代理对象,借助代理对象对目标对象进行功能上的增强而不需要修改原有的代码,比如在维护期想要给某些对象添加相应的日志监控,这时候就可以生成代理对象来操作。
代理的分类:
1、静态代理
静态代理中代理类的代码需要我们手动去实现,在编译期间代理类的class文件就已经存在了。
下面直接上代码
/** * 代理类和目标类的通用接口 */ public interface Subject { public String request(); } /** * 目标类 */ public class RealSubject implements Subject{ public String request(){ system.out.println("目标主题的内容"); } } /** * 代理类 */ public class ProxySubject implements Subject{ RealSubject subject; public ProxySubject(RealSubject subject){ this.subject = subject; } public String request(){ system.out.println("代理类调用目标类之前"); subject.request(); system.out.println("代理类调用目标类之后"); } } /** * 静态代理测试类 */ public class StaticProxyTest{ public static void main(String[] args) { RealSubject real = new RealSubject(); ProxySubject proxy = new ProxySubject(real); proxy.request(); } }
静态代理首先创建代理类,与目标类实现相同的接口方法,然后在代理方法中调用目标对象的方法,通过调用代理对象来使用目标对象的功能,这样做可以在不修改目标对象的情况下对目标对象进行功能性扩展,但是缺点是如果接口添加新的方法,代理对象和目标对象都要进行修改。
2、jdk动态代理
jdk动态代理使用了JDK的API,不需要预先实现代理类,而是动态的在内存中构建代理对象。
/** * 需要实现的目标接口 */ public interface Subject{ public void request(); } /** * 具体目标类 */ public class JDKProxySubject{ public void request(){ system.out.println("目标对象执行内容"); } } /** * jdk动态代理测试类 */ public class JDKProxyTest{ public static void main(String[] args) { final Subject dao = new JDKProxySubject(); Subject proxy =(Subject)Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), new InvocationHandler(){ /** * proxy 代理对象 * method 被代理对象方法 request() * args request方法的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("动态代理类方法开始"); //执行目标对象的request方法,传入的是args参数,返回值是result method.invoke(dao, args); System.out.println("动态代理类方法结束"); return null; } }); System.out.println("======="+开始+"======="); proxy.request(); } }
所有目标对象中的方法都由代理对象中的invoke方法调用,invoke方法的三个参数
proxy:代理对象
method:目标对象中被调用的方法
args:目标对象中方法的入参
Proxy常用的创建代理对象的方法是newProxyInstance
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler )
该方法是静态方法,接收的参数为
- ClassLoader loader:指定当前目标对象使用类加载器
- Class<?>[] interfaces:目标对象实现的所有接口的类型,使用泛型方法确定类型
- InvocationHandler handler:事件处理,执行代理对象的方法,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
3、cglib动态代理
cglib代理与以上两种代理模式有所不同,以上两种代理模式都要求目标对象实现一个接口,而有时候目标对象仅仅只是一个单独的对象,并没有实现接口,这个时候便可以使用以目标对象子类的方法实现代理,这就是cglib代理。
cglib代理也叫子类代理,它是在内存中构建一个子类对象,从而实现对于目标对象的代理,springAOP中也用到了cglib。
要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入spring-corr.jar即可。
1.引入功能包后,就可以在内存中动态构建子类
2.代理的类不能为final,否则报错
3.目标对象的方法如果为final/static,那么就不会被拦截,就不会执行目标对象额外的业务方法/** * 目标对象类,没有实现任何接口 */ public class Subject{ public void request(){ system.out.println("目标对象中的方法正在执行"); } } /** * Cglib子类代理工厂 */ public class ProxyFactory implements MethodInterceptor{ private Object target; public ProxyFactory(Object target){ this.target = target; } public Object getProxyInstance(){ //工具类 Enhancer enhancer = new Enhancer(); //设置父类 enhancer.setSuperclass(target.getClass()); //设置回调函数 enhancer.setCallback(this); //创建子类(代理对象) return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("开始事务..."); //执行目标对象的方法 Object returnValue = method.invoke(target, args); System.out.println("提交事务..."); return returnValue; } } } /** * cglib代理测试类 */ public class CglibProxyTest{ public static void main(String[] args) { //创建目标对象 Subject target = new Subject(); //生成cglib代理对象 Subject proxy = (Subject)new ProxyFactory(target).getProxyInstance(); //执行代理对象的request方法 proxy.request(); } }