代理模式是指为其他对象提供一个代理以控制该对象的访问。代理类主要负责为委托预处理消息、过滤消息、传递消息给委托类,代理类不实现具体服务,而是利用委托类来完成服务,并执行结果封装处理。
其实就是代理类为被代理类预处理消息,过滤消息并在此之后将小心转发给被代理类,之后还能进行消息的后置处理。使用代理对象,是为了在不修改目标对象的基础上,增强主业务。
实现代理的方式:
1,静态代理:
- 代理类是自己手工实现的,自己创建一个java类,表示代理类。
- 同时你所要代理的目标类也是确定的。
2,动态代理:动态代理可以避免静态代理的缺点。动态代理中目标类即使很多,代理类对象可以很少,当修改了接口中的方法时,不会影响代理类。
静态代理
创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时也实现该接口。在代理类中持有一个被代理对象的引用,而在代理类方法中调用该对象的方法。
接口:
//租房接口 public interface RentHouse { void rent(); }
被代理类
//客户租房 public class Customer implements RentHouse { @Override public void rent() { System.out.println("我要租房"); } }
代理类
//中介 public class HouseProxy implements RentHouse { private RentHouse rentHouse=new Customer(); @Override public void rent() { System.out.println("带租户看房"); rentHouse.rent(); System.out.println("签订合同"); } }
代理类调用
被代理类被传递给了代理类,代理类在执行具体方法时通过所持有的被代理类完成代理。
public static void main(String[] args) { HouseProxy houseProxy=new HouseProxy(); houseProxy.rent(); }
使用静态代理很容易就完成了对一个类的代理操作。但是静态代理的缺点也暴露出来:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。
代理类完成的功能:
- 目标类中方法的调用
- 功能增强
动态代理
动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的.java文件。
动态代理的实现方式:
- JDK动态代理
- CGLIB动态代理
JDK动态代理:
使用java反射包中的类和接口实现动态代理的功能。反射包中java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy。
1,InvocationHandler接口:就一个方法invoke()方法。表示代理对象要执行的功能代码。
/**方法原型: 参数: Object proxy:jdk创建的代理对象,无需赋值 Method method:目标类中的方法,jdk提供method对象 Object[] args:目标类中方法的参数,jdk提供 **/ public Object invoke(Object proxy, Method method, Object[] args)
Invocation接口:表示代理对象要执行的功能。创建类实现接口InvocationHandler,重写invoke()方法。
2,Method类:表示方法的,确切的说就是目标类中的方法。
通过执行Method可以执行某个目标类的方法,Method.invoke()
3,Proxy类:核心对象,创建代理对象。
使用静态方法newProxyInstance()方法,创建代理对象。
/** ClassLoader loader:类加载器,负责向内存中加载对象的。使用反射获取目标对象的ClassLoader。 Class<?>[] interfaces:接口,目标对象实现的接口,也是反射获取的。 InvocationHandler h:代理类要完成的功能 返回值就是代理对象 **/ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
实现动态代理的步骤:
- 创建接口,定义目标类要完成的功能。
- 创建目标类实现接口。
- 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能(调用目标方法;增强功能)
- 使用Proxy类的静态方法,创建代理对象,并把返回值转换为接口类型。
目标接口
public interface UsbSell { float sell(int amount); }
目标类
public class UsbFactory implements UsbSell { @Override public float sell(int amount) { //目标方法 System.out.println("目标类中,执行sell目标方法"); return 80.0f; } }
InvocationHandler对象
public class MyHandler implements InvocationHandler { //目标对象 private Object target; //动态代理:目标对象是活动的,不是固定的,需要传入进来 public MyHandler(Object target){ //给目标对象赋值 this.target=target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //执行目标类中的目标方法 Object object = method.invoke(target, args); //执行增强方法 if(object!=null){ Float price=(Float)object; price=price+20; object=price } System.out.println("商家返回一个红包"); return object; } }
测试类
public class Solution { public static void main(String[] args) { //1,创建目标类对象 UsbFactory usbFactory = new UsbFactory(); //2,创建InvocationHandler对象 MyHandler myHandler = new MyHandler(usbFactory); //3,创建代理对象 UsbSell usbSell = (UsbSell) Proxy.newProxyInstance(usbFactory.getClass().getClassLoader(), usbFactory.getClass().getInterfaces(), myHandler); //4,通过代理执行方法 float sell = usbSell.sell(2); System.out.println("通过代理执行的结果:"+sell); } }
cgLib动态代理:
cglib动态代理的原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。所以使用cglib生成动态代理,要求目标类能够被继承,即不能是final的类。

代理类继承目标类,每次嗲用代理类的方法都会被方法拦截器拦截,在拦截器中才是调用目标类中的方法。
1,导入cglib的依赖
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency>
2,创建目标类
public class Dog { public final void run(String name){ System.out.println("狗 "+name+" 跑"); } public void eat(){ System.out.println("狗 ----eat"); } }
3,方法拦截器
public class MyMethodInceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("这里是对方法的增强"); //这里的方法调用不是反射 Object object = methodProxy.invokeSuper(o, objects); return object; } }
4,测试类
public class CGTest { public static void main(String[] args) { MyMethodInceptor myMethodInceptor = new MyMethodInceptor(); //创建Enhance对象,类似于JDK动态代理的Proxy类 Enhancer enhancer = new Enhancer(); //设置目标类的字节码文件 enhancer.setSuperclass(Dog.class); //设置回调函数 enhancer.setCallback(myMethodInceptor); //创建代理类对象 Dog dog =(Dog) enhancer.create(); //调用代理类中的方法 dog.eat(); } }
cglib动态代理主要调用步骤:
1)是经过一系列操作实例化Enhance对象,并设置了所需要的参数然后enhancer.create()创建代理对象。
2)调用代理对象的eat()方法,会进入到方法拦截器的intercept()方法,在这个方法中会调用proxy.invokeSuper(obj,args)方法。
3)invokeSuper中,通过FastClass机制调用目标类的方法。
posted on
浙公网安备 33010602011771号