门户网站收录,网站架构师工资,鞋网站建设,seo网站架构这里写目录标题 什么是代理1.静态代理#xff08;委托类、代理类#xff09;#xff1a;使用步骤#xff1a;示例优缺点 2.动态代理#xff08;委托类、中介类#xff09;2.1 JDK动态代理使用#xff1a;中介类#xff1a;示例1#xff1a;示例2#xff1a; 2.2 CGLi… 这里写目录标题 什么是代理1.静态代理委托类、代理类使用步骤示例优缺点 2.动态代理委托类、中介类2.1 JDK动态代理使用中介类示例1示例2 2.2 CGLib动态代理使用方法目标类原始类不能为final示例1示例2 什么是代理
代理模式是一种设计模式简单说即是在不改变源码的情况下实现对目标对象的功能扩展。 比如有个歌手对象叫Singer这个对象有一个唱歌方法叫sing()
1 public class Singer{
2 public void sing(){
3 System.out.println(唱一首歌);
4 }
5 }假如你希望对目标对象Singer的sing方法进行功能扩展例如在唱歌前后向观众问好和答谢类似这样
1 public void sing(){
2 System.out.println(向观众问好);
3 System.out.println(唱一首歌);
4 System.out.println(谢谢大家);
5 } 但是又不能直接对源代码进行修改甚至有可能你都不知道要对哪个目标对象进行扩展。这时就需要用到java的代理模式了。
1.静态代理委托类、代理类
静态代理要求原始类有实现某个接口。 需要创建一个代理类实现和原始类相同的接口并在需要增强的方法里调用原始类的该方法调用前后加上我们需要添加的代码。 使用的时候直接创建一个代理类实例调用目标方法即可。
使用步骤
共同接口
public interface Action {public void doSomething();
}原始类
public class RealObject implements Action{public void doSomething() {System.out.println(do something);}
}代理类
public class Proxy implements Action {private Action realObject; public Proxy(Action realObject) {this.realObject realObject;}public void doSomething() {System.out.println(proxy do);realObject.doSomething();}
}使用
Proxy proxy new Proxy(new RealObject());
proxy.doSomething();示例
public interface ISinger {void sing();
}/*** 目标对象实现了某一接口*/
public class Singer implements ISinger{public void sing(){System.out.println(唱一首歌);}
}/*** 代理对象和目标对象实现相同的接口*/
public class SingerProxy implements ISinger{// 接收目标对象以便调用sing方法private ISinger target;public UserDaoProxy(ISinger target){this.targettarget;}// 对目标对象的sing方法进行功能扩展public void sing() {System.out.println(向观众问好);target.sing();System.out.println(谢谢大家);}
}测试类
/*** 测试类*/
public class Test {public static void main(String[] args) {//目标对象ISinger target new Singer();//代理对象ISinger proxy new SingerProxy(target);//执行的是代理的方法proxy.sing();}
}总结这里做的事情无非就是创建一个代理类SingerProxy继承原始类的ISinger接口实现其中的方法并在实现中调用目标对象的方法。这里的关键是“调用目标对象方法”如果直接重写就不叫代理了。
优缺点
优点扩展原功能不侵入原代码。
缺点 ①冗余。由于代理对象要实现与目标对象一致的接口会产生过多的代理类。 ②不易维护。代理对象必须提前写出一旦接口发生了变化代理对象的代码也要进行维护。
2.动态代理委托类、中介类
代理类在程序运行时运用反射机制创建的代理方式被成为动态代理。 也就是说代理类并不是在Java代码中定义的而是在运行时根据我们在Java代码中的“指示”动态生成的。 相比于静态代理 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理而不用修改每个代理类的函数。
2.1 JDK动态代理
同样要求原始类实现某个接口但不用手动创建代理类而是创建中介类。中介类实现InvocationHandler接口。
使用
调用Proxy类中的newProxyInstance(ClassLoader loader,Class?[] interfaces,InvocationHandler h)方法以创建一个动态代理对象其中第三个参数为我们创建的实现InvocationHandler接口的类中介类前两个参数可通过目标类.getclass().getxxx获取。
中介类
需实现InvocationHandler接口包含一个Object类型的对象并利用其编写中介类的有参构造函数。重写的方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable里proxy表示代理类对象 method标识了我们具体调用的代理类的方法args为这个方法的参数。
示例1
public interface ISinger {void sing();
}/*** 目标对象实现了某一接口*/
public class Singer implements ISinger{public void sing(){System.out.println(唱一首歌);}
}-------------------------public class Test{public static void main(String[] args) {Singer target new Singer();//这行要自己写ISinger proxy (ISinger) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(向观众问好);//目标对象方法前后编写需要扩展的代码Object returnValue method.invoke(target, args);System.out.println(谢谢大家);return returnValue;}});proxy.sing();}
}示例2 public static void main(String[] args) throws InterruptedException {EnHello enHellonew EnHello();Hello hello(Hello)Proxy.newProxyInstance(enHello.getClass().getClassLoader(),enHello.getClass().getInterfaces(), new MyInvocationHandler(enHello));hello.sayHello(Tom);}interface Hello{String sayHello(String username);
}static class EnHello implements Hello{Overridepublic String sayHello(String username) {System.out.println(Hello, username);return finished;}
}static class MyInvocationHandler implements InvocationHandler{private Object object;public MyInvocationHandler(Object object){this.objectobject;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object resultnull;System.out.println(before say hello);if(sayHello.equals(method.getName())){resultmethod.invoke(object,args);}System.out.println(before say hello);return result;}
}还可以只为指定方法动态代理在invoke方法加上以下判断
String methodName method.getName();
if(eating.equals(methodName))method.invoke(obj,args);优点一可以隐藏委托类的实现; 优点二可以实现客户与委托类间的解耦在不修改委托类代码的情况下能够做一些额外的处理
2.2 CGLib动态代理
JDK动态代理和cglib动态代理有什么区别
使用JDK动态代理的对象必须实现一个或多个接口 使用cglib代理的对象则无需实现接口。
cglib可以对任意类生成代理对象它的原理是对目标对象进行继承代理所以如果目标对象被final修饰那么该类无法被cglib代理。
使用方法
导包-创建MethodInterceptor实现类
使用cglib需要引入cglib的jar包如果你已经有spring-core的jar包则无需引入因为spring中包含了cglib。
目标类原始类不能为final
目标对象的方法如果为final/static那么就不会被拦截即不会执行目标对象额外的业务方法
示例1
/*** 目标对象,没有实现任何接口*/
public class Singer{public void sing() {System.out.println(唱一首歌);}
}----------------------/*** Cglib子类代理工厂*/
public class ProxyFactory implements MethodInterceptor{// 维护目标对象private Object target;public ProxyFactory(Object target) {this.target target;}// 给目标对象创建一个代理对象public Object getProxyInstance(){//1.工具类Enhancer en new Enhancer();//2.设置父类en.setSuperclass(target.getClass());//3.设置回调函数en.setCallback(this);//4.创建子类(代理对象)return en.create();}/*
使用时只有intercept方法中代码行 method.invoke前后的代码需要修改其他的代码直接使用
*/Overridepublic 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;}
}-----------------------/*** 测试类*/
public class Test{public static void main(String[] args){//目标对象Singer target new Singer();//代理对象Singer proxy (Singer)new ProxyFactory(target).getProxyInstance();//执行代理对象的方法proxy.sing();}
}示例2
public class TestCglib implements MethodInterceptor { Object target; //动态生成一个新的类使用父类的无参构造方法创建一个指定了特定回调的代理实例 public Object getProxyObject(Object object) { this.target object; //增强器动态代码生成器 Enhancer enhancernew Enhancer(); //回调方法enhancer.setCallback(this); //设置生成类的父类类型 enhancer.setSuperclass(target.getClass()); //动态生成字节码并返回代理对象 return enhancer.create(); }public Object intercept(Object o, Method method, Object[] objects, MethodProxy
methodProxy) throws Throwable {System.out.println(----------before); // 调用方法 Object result methodProxy.invoke(target, objects); System.out.println(----------after); return null; }
}//使用
public static void main(String[] args) {Boss boss(Boss) new TestCglib().getProxyObject(new Boss());boss.eating();boss.sleeping();
}