代理模式:
给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问。代理模式是一种结构型设计模式。
代理模式有三种:
- Subject(抽象主题角色):定义代理类和真实主题的公共对外方法,通常被设计成接口
- RealSubject(真实主题角色):真正实现业务逻辑的类;
- Proxy(代理主题角色):用来代理和封装真实主题;
代理模式的结构比较简单,其核心是代理类,为了让客户端能够一致性地对待真实对象和代理对象,在代理模式中引入了抽象层。
如果根据字节码的创建时机来分类,可以分为静态代理和动态代理:
●所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。
●而动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件
一、静态代理
实现过程
1.首先定义一个接口,接口定义代理类和目标类的实现方法
public interface UserService {
public void update();
public void select();
}
2.创建接口的实现类
public class UserServiceImpl implements UserService{
@Override
public void update() {
System.out.println("更新");
}
@Override
public void select() {
System.out.println("查询");
}
}
3.静态代理也实现该方法
public class UserServiceProxy implements UserService{
private UserServiceImpl realUserService=new UserServiceImpl();
@Override
public void update() {
long begin=System.currentTimeMillis();
realUserService.update();
long end=System.currentTimeMillis();
System.out.println();
}
@Override
public void select() {
realUserService.select();
System.out.println();
}
}
4.测试
public interface Test {
public static void main(String[] args) {
UserServiceProxy userproxy=new UserServiceProxy();
userproxy.select();
System.out.println();
userproxy.update();
System.out.println();
}
}
静态代理的优缺点
优点:
通过静态代理,我们达到了功能增强的目的,而且没有侵入原代码,这是静态代理的一个优点。
缺点:
虽然静态代理实现简单,且不侵入原代码,但是,当场景稍微复杂一些的时候,静态代理的缺点也会暴露出来。1、 当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类2、 当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。
二、动态代理
动态代理实在运行过程中进行动态创造的,Java中两种常见的动态代理方式:JDK原生动态代理和CGLIB动态代理(第三方开源类库)。
JDK动态代理主要涉及两个类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler。
JDK动态代理实现过程
动态代理处理类
public class PerformanceInvocationHandler implements InvocationHandler {
private Object real;
public PerformanceInvocationHandler(Object real) {
this.real=real;
}
/**
* 参数:proxy
* 参数:method
* 参数:args
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long begin=System.currentTimeMillis();
//真实业务对象当前执行方法基于反射方式
Object returnValue=method.invoke(real, args);
long end =System.currentTimeMillis();
System.out.println("方法耗时"+(end-begin)+"毫秒");
return returnValue;
}
}
测试
public class Test1 {
public static void main(String[] args) {
//真实主题对象
OrderServiceImpl realOrderService=new OrderServiceImpl();
//获取类加载器
ClassLoader loader=realOrderService.getClass().getClassLoader();
//获取真实的类继承的接口
//因为一个类可以实现多个接口所有用Class[] 数组接收
Class[] interfaces=realOrderService.getClass().getInterfaces();
//创建InvocationHander对象(动态代理执行的逻辑)
PerformanceInvocationHandler h= new PerformanceInvocationHandler(realOrderService);
//创建动态代理
OrderService orderProxy=(OrderService)Proxy.newProxyInstance(loader, interfaces, h);
orderProxy.service1(12.0, 0001);
}
}
CGLIB动态代理
基于子类的动态代理(第三方 Cglib)CGlib方式是基于继承实现的代理,它不是指真实类需要继承某个父类,而是生成的代理类作为真实类的子类去代理父类,即代理类继承自真实类。这种方式不需实现接口,可以作为JDK代理方式的补充方案。\n\n CGLIB(Code Generation Library)是一个基于ASM(Java字节码操作框架)实现的代码生成库,它可以在运行时动态生成目标类的子类作为代理类,并覆盖其中的方法来实现代理功能。与Java自带的JDK动态代理不同,CGlib动态代理可以代理没有实现接口的类。
三、静态代理和动态代理的区别
- 生成方式:静态代理需要手动编写或自动生成.java源文件,而动态代理通过Java反射机制动态地创建类;
- 扩展性:静态代理扩展性较差,因为一旦.class文件生成就不能再改变行为,而动态代理扩展性较好,可以方便地改变行为;
- 代码结构:静态代理的代码结构较为简单明了,而动态代理的代码结构稍微复杂一些,需要实现InvocationHandler接口和处理Method对象;
- 性能:静态代理的性能略优于动态代理,因为静态代理可以提前编译成本地代码,而动态代理需要在运行时动态创建类;
- 适用场景:静态代理适用于简单扩展场景,而动态代理适用于复杂的扩展场景。