代理模式是一种设计模式。
使用代理对象来替代真实对象,用代理对象去访问目标对象。这样可以保证在不修改目标对象的前提下,还可以增加一些额外的功能,作出扩展。
代理模式的作用主要是扩展目标对象的功能,在目标对象执行方法的前后,可以自己自定义一些操作。
同时代理模式分为静态代理和动态代理
静态代理对目标对象的方法增强要手动完成,如果接口增加了新的方法,那么就要更改代码,不够灵活,开发中比较少见静态代理。
JVM层面:
静态代理在编译期讲接口,和接口的实现类,代理类都变成class文件。
静态代理实现:
1. 定义接口A和实现类 (也就是要传输的内容)
2. 创建一个代理类实现接口A (代理类要可以接收传输的内容)
3. 将目标对象注入到代理类中,在代理类的方法中调用目标对象的方法,然后在目标对象方法执行的前后 就可以扩展一些内容。
代码:
1.定义发送内容的接口
package 静态代理;
// 1.定义发送内容的接口 目标对象
public interface Message {
String send(String message);
}
2.实现发送短信的接口
package 静态代理;
//2. 发送内容接口的实现类 就是目标对象处理传输的内容的处理方法
public class MessageImpl implements Message {
@Override
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
3.创建代理类并实现接口
package 静态代理;
//3. 代理类 也需要实现接口 且需要将目标对象注入到其中来 代理对象
public class MessageProxy implements Message {
//目标对象(Message)注入到代理类中
private final Message Message;
public MessageProxy(Message message) {
this.Message = message;
}
@Override
public String send(String message) {
//方法执行前 添加自定义内容
System.out.println("before method send()");
//在代理类中的方法 调用目标类的方法
Message.send(message);
//方法执行后 添加自定义内容
System.out.println("after method send()");
return null;
}
}
4.执行代码
public class Main {
public static void main(String[] args) {
System.out.println("静态代理");
//实例化 实现类对象 类型是Message 目标对象
//Message sendMessage = new MessageImpl();
MessageImpl sendMessage = new MessageImpl();
//实例化 代理类对象 完成注入 代理对象
MessageProxy messageProxy = new MessageProxy(sendMessage);
//执行方法
messageProxy.send("hello");
}
}
对于静态代理来说,动态代理更加灵活,不需要保证每个目标类都有一个代理类,实现接口也不是必须的,可以直接代理实现类。
JVM层面:
动态代理是在运行时动态生成类字节码,加载到JVM中。
举例:
Spring AOP ,RPC框架使用了动态代理。
动态代理对于框架的学习帮助较大。
动态代理实现方法很多 ,这篇介绍 JDK动态代理和CGLIB动态代理。
JDK动态代理中 InvocationHandler接口和Proxy类是重点。
Proxy类中有一个方法:newProxyInstance() 用来生成代理对象。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
......
}
Proxy类中的newProxyInstance()方法有三个参数:
1.loader:类加载器,用来加载代理对象。
2.interfaces: 被代理类实现的一些接口。
3.h: 实现了InvocationHandler接口的对象。
动态代理还需要实现InvocationHandler接口,自定义处理内容的逻辑,这样我们在代理对象调用一个方法的时候,方法会转发到InvocationHandler接口类中的invoke方法。
public interface InvocationHandler {
/**
* 当你使用代理对象调用方法的时候实际会调用到这个方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
InvocationHandler接口中的invock方法有三个参数:
**1.proxy:**动态生成的代理类。
**2.method:**与代理类调用的方法对应
**3.args:**method方法的参数
动态代理机制:通过Proxy类的newProxyInstance方法 创建的代理类在调用方法的时候,实际调用的InvocationHandler接口中的Invoke方法。
所以需要在Invoke方法中自定义内容。
JDK动态代理实现:
1.定义一个接口和实现类
2.重写InvocationHandler中的Invoke()方法,用来自定义内容。
3.通过Proxy类的newProxyInstance()方法创建代理对象。
代码:
1.定义发送内容的接口
package JDK动态代理;
//目标对象
public interface SdMessage {
String send(String message);
}
2.发送内容接口的实现类
package JDK动态代理;
//实现接口的实现类 就是目标对象处理传输的内容的处理方法
public class SdMessageImp implements SdMessage {
@Override
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
3.重写InvocationHandler中的Invoke方法
package JDK动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//代理类调用方法时 调用的是InvocationHandler中的Invoke方法 重写它 自定义
public class MyInvocationHandler implements InvocationHandler {
/**
* 代理类中的真实对象
*/
private final Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
//其中的method和代理类调用的方法对应
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法调用前,自定义的内容
System.out.println("before method() " + method.getName());
Object result = method.invoke(target,args);
//方法调用后,自定义的内容
System.out.println("after method() " + method.getName());
return result;
}
}
4.创建代理类
package JDK动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//代理类调用方法时 调用的是InvocationHandler中的Invoke方法 重写它 自定义
public class MyInvocationHandler implements InvocationHandler {
/**
* 代理类中的真实对象
*/
private final Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
//其中的method和代理类调用的方法对应
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法调用前,自定义的内容
System.out.println("before method() " + method.getName());
Object result = method.invoke(target,args);
//方法调用后,自定义的内容
System.out.println("after method() " + method.getName());
return result;
}
}
5.执行
public class Main {
public static void main(String[] args) {
//JDK动态代理 其中的参数是目标对象
System.out.println("JDK动态代理");
SdMessage sdMessage = (SdMessage) ProxyFactory.getProxy(new SdMessageImp());
sdMessage.send("hello");
}
}
JDK动态代理的缺点是 只可以代理已经实现了接口的实现类。
而CGLIB动态代理可以避免。
CGLIB是一个基于ASM的字节码生成库,允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理,很多开源框架都使用到了CGLIB,例如Spring中的AOP模块中,如果实现了接口那么就采用JDK动态代理,如果没实现,就使用CGLIB动态代理。
CGLIB动态代理中 MethodInterceptor接口和Enhancer类是重点
需要重写MethodInterceptor接口中的Intercept方法,这个方法用来拦截被代理类。
public interface MethodInterceptor
extends Callback{
// 拦截被代理类中的方法
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
**MethodInterceptor接口中的Intercept()**方法有4个参数:
1.obj:被代理的对象(也可以叫做需要增强的对象)
2.method:被拦截的方法(也可以叫做需要增强的方法)
3.args:方法的参数
4.proxy:用于调用原始方法
可以通过Enhancer类来动态获取被代理类,当代理类调用方法的时候,实际调用的是MethodInterceptor接口中的Intercept方法。
CGLIB动态代理实现:
1.定义一个类
2.重写MethodInterceptor接口中的Intercept()方法,这个方法用来拦截被代理类的方法,其实也就是拦截到方法以后,会执行intercept方法,和被代理类的方法。
3.通过Enhancer类的create()方法创建代理类。
CGLIB动态代理代码实现:
CGLIB是开源项目需要引入依赖。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
1.实现一个发送消息的类
package CGLIB动态代理;
//发送内容的类
public class CglibSdMessage {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
2.自定义MethodInterceptor(方法拦截器)重写其中的Intercept方法
package CGLIB动态代理;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
//方法拦截器 重写MethodInterceptor接口中的intercept方法
public class MyMethodInterceptor implements MethodInterceptor {
/**
*
* @param o 被代理的对象(需要增强的对象)
* @param method 被拦截的方法(需要增强的方法)
* @param objects 方法的参数
* @param methodProxy 用于调用原始方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//方法调用前,自定义的内容
System.out.println("before method() " + method.getName());
Object object = methodProxy.invokeSuper(o,objects);
//方法调用后,自定义的内容
System.out.println("after method() " + method.getName());
return object;
}
}
3.获取代理类(创建代理类)
package CGLIB动态代理;
import net.sf.cglib.proxy.Enhancer;
//创建代理类 通过Enhancer类的create方法
public class CglibProxyFactory {
//Class> clazz之前接收的是实现接口的实现类 现在接收的是类 泛型
public static Object getProxy(Class<?> clazz) {
//创建动态代理类
Enhancer enhancer = new Enhancer();
//设置类加载器
enhancer.setClassLoader(clazz.getClass().getClassLoader());
//设置被代理类(目标对象)
enhancer.setSuperclass(clazz);
//设置方法拦截器
enhancer.setCallback(new MyMethodInterceptor());
//创建代理类
return enhancer.create();
}
}
4.调用
public class Main {
public static void main(String[] args) {
//CGLIB动态代理 其中的参数是被代理类(目标对象)
System.out.println("JDK动态代理");
CglibSdMessage cglibSdMessage = (CglibSdMessage) CglibProxyFactory.getProxy(CglibSdMessage.class);
cglibSdMessage.send("hello");
}
}
我在文章中介绍了静态代理和动态代理,包阔了静态代理的代码实现和动态代理中的2钟代理(JDK动态代理和CGLIB动态代理)的代码实现,已经静/动态代理的区别,和两种动态代理的区别。