代理模式
代理模式是指客户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象。
springboot 的aop(面向切面编程) 就是使用了代理的思想,
1. 静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类
。
缺点:
因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要重新维护.
2. Demo
/**
* @Author laijinhan
* @date 2020/12/14 下午9:09
*/
/**
* 抽象产品接口
*/
interface UserService {
public void getName();
public void getAddress();
}
/**
* 具体产品实现类
*/
class UserServiceImpl implements UserService{
@Override
public void getName() {
System.out.println("我是赖金寒");
}
@Override
public void getAddress() {
System.out.println("居住在成都郫县");
}
}
/**
* 产品代理类
*/
public class StaticProxy implements UserService {
private UserService target;
public StaticProxy(UserServiceImpl target) {
this.target=target;
}
@Override
public void getName() {
System.out.println("静态代理执行之前");
target.getName();
System.out.println("静态代理执行之后");
}
@Override
public void getAddress() {
System.out.println("静态代理执行之前");
target.getAddress();
System.out.println("静态代理执行之后");
}
public static void main(String[] args) {
new StaticProxy(new UserServiceImpl()).getName();
System.out.println("====");
new StaticProxy(new UserServiceImpl()).getAddress();
}
}
2. 动态代理
动态代理也称为JDK代理,接口代理,利用反射机制在运行时创建代理类
。
接口、被代理类不变(上面写的UserService、UserServiceImpl类),有两种方式实现:
- 实现InvocationHandler接口的话就要,就要在Proxy.newProxyInstance第三个参数传入this,并重写invoke方法(代理对象执行事件处理)。
- 也可以不实现InvocationHandler接口,只是在Proxy.newProxyInstance传入第三个参数时,重写InvocationHandler接口的invoke方法;
动态代理不需要实现产品接口。
步骤:
- 实现 InvocationHandler 接口创建代理类;
- 设置被代理的接口(具体的产品类)
- 生成代理对象(Proxy类的静态方法newProxyInstance,需要传入当前目标对象使用的类加载器,代理对象实现的产品接口,执行的事件处理器)
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
2.1 Demo
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 实现方式一
class DynamicProxy0 implements InvocationHandler {
private Object target; //被代理的任意接口
public DynamicProxy0(Object target){
this.target=target;
}
public Object getProxyInstance() { //生成代理类
return Proxy.newProxyInstance(
this.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理执行之前");
//执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("动态代理执行之后");
return returnValue;
}
public static void main(String[] args) {
// 具体的产品类
UserServiceImpl userService = new UserServiceImpl();
// 动态代理类,获取代理对象
UserService proxyInstance = (UserService)new DynamicProxy0(userService).getProxyInstance();
// 获取代理对象
proxyInstance.getName();
}
}
// 动态代理对象实现方式二
public class DynamicProxy {
private Object target; //被代理的任意接口
public DynamicProxy(Object target){
this.target=target;
}
public Object getProxyInstance() { //生成代理类
return Proxy.newProxyInstance(
this.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("动态代理执行之前");
//执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("动态代理执行之后");
return returnValue;
}
);
}
public static void main(String[] args) {
// 具体的产品类
UserServiceImpl userService = new UserServiceImpl();
// 动态代理类,获取代理对象
UserService proxyInstance = (UserService)new DynamicProxy(userService).getProxyInstance();
// 获取代理对象
proxyInstance.getAddress();
}
}
3. Cglib
上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象
,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理。
Cglib代理,也叫作子类代理
,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展
.
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
在Springboot中,如果加入容器的对象实现了接口类,那么就是JDK代理;没有实现就是Cglib代理。
Maven 需要导入spring-core的包
Demo
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Author laijinhan
* @date 2020/12/14 下午9:52
*/
/**
* CglibProxy通过创建子类来实现动态代理
*/
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(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();
}
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("动态代理执行之前");
//执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("动态代理执行之后");
return returnValue;
}
public static void main(String[] args) {
UserService proxyInstance = (UserService) new CglibProxy(new UserServiceImpl()).getProxyInstance();
proxyInstance.getAddress();
}
}