代理是一种设计模式,提供了对目标对象其他的访问方式,即通过代理对象访问目标对象。
优点是可以在目标对象实现的基础上,扩展一些功能。
例如:格力工厂生产了很多空调,通过各地的经销商来卖空调,这种通过经销商卖空调的模式就是代理模式。
常见的代理模式分为静态代理和动态代理,动态代理在Java中的实现分为JDK动态代理和CGLIB代理。
如果目标对象实现了接口,则会采用JDK动态代理。
如果目标对象没有实现接口,则会默认采用CGLIB代理。
静态代理和动态代理模式主要涉及三个角色:
Service:接口,该接口是对象和它的代理共用的接口
TargetObject:目标对象,是抽象接口的实现类
Proxy:代理对象,内部含有对TargetObject的引用,可以操作真实对象,代理对象也会实现该抽象接口,代理对象在执行目标对象操作时,扩展了其他的操作。
动态代理:
称为JDK代理,接口代理,动态代理就是在程序运行过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程,代理的目的也是调用目标对象时可以转而执行InvocationHandler的invoke方法,主要依赖Proxy类的newProxyInstance方法。
JDK动态代理基于接口的原因:
生成的代理类继承了Proxy,由于Java是单继承,所以只能实现接口
CGLIB代理:
静态代理和动态代理模式都要求目标对象要实现一个接口,但是有的时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可以使用CGLIB代理。
CGLIB采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的方式拦截所有父类方法的调用,顺势织入横切逻辑。
使用注意:
1、代理的类不能为final类
2、目标对象的方法如果为final或者static,那么就不会被拦截
静态代理的代码示例:
1、定义一个售卖接口SellService,里边包含一个卖空调的方法
public interface SellService {
//卖空调
void sellAirConditioner();
}
2、编写SellService的实现类SellServiceImpl,实现卖空调的方法
public class SellServiceImpl implements SellService {
@Override
public void sellAirConditioner() {
System.out.println("我卖的是格力空调,请大家赶快来购买,有88折优惠。");
}
}
3、编写一个经销商DealerProxy来卖空调,通过构造方法注入SellService接口,在调用卖空调方法前后扩展一些其他的服务,如支付,安排配送、入户安装等。
public class DealerProxy implements SellService{
SellService sellService;
public DealerProxy(SellService sellService) {
this.sellService = sellService;
}
@Override
public void sellAirConditioner() {
System.out.println("签订合同,支付空调费用");
sellService.sellAirConditioner();
System.out.println("安排师傅配送到家,帮用户安装空调。");
}
}
4、写个测试类
public class ProxyTest {
public static void main(String[] args) {
SellService sellService = new SellServiceImpl();
DealerProxy proxy = new DealerProxy(sellService);
proxy.sellAirConditioner();
}
}
5、测试结果
动态代理
动态代理涉及了一个非常重要的类Proxy,正是通过Proxy的静态方法newProxyInstance才会动态创建代理。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
ClassLoader:类加载器
interfaces:代码要用来代理的接口
InvocationHandler:代理的类实现该接口,如果代理的方法被调用,那么代理便会通知和转发给内部的InvocationHandler实现类。
代码事例如下:
1、先定一个接口SellService
public interface SellService {
//卖空调
void sellAirConditioner();
}
2、编写该接口的实现类SellServiceImpl
public class SellServiceImpl implements SellService {
@Override
public void sellAirConditioner() {
System.out.println("我卖的是格力空调,请大家赶快来购买,有88折优惠。");
}
}
3、编写一个代理类TotalDealerProxy实现InvocationHandler接口,在invoke方法中扩展一些逻辑
public class TotalDealerProxy implements InvocationHandler {
SellService sellService;
public TotalDealerProxy(SellService sellService) {
this.sellService = sellService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("够买前,我在总经销商这里拿到了一些赠品饮水机");
Object result = method.invoke(sellService,args);
System.out.println("购买后,赠送负责入户安装的服务");
return result;
}
}
4、编写测试类
public class DealerProxyTest {
public static void main(String[] args) {
SellService service = new SellServiceImpl();
TotalDealerProxy proxy = new TotalDealerProxy(service);
SellService ss = (SellService)Proxy.newProxyInstance(service.getClass().getClassLoader(),service.getClass().getInterfaces(),proxy);
ss.sellAirConditioner();
}
}
5、测试结果
CGLIB代理:
cglib代理,也叫子类代理,它是在内存中构建一个子类对象从而实现对目标对象的扩展功能。
CGLIB采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的方式拦截所有父类方法的调用,顺势织入横切逻辑。
接口的代码示例如下:
1、先创建一个接口SellService
public interface SellService {
//卖空调
void sellAirConditioner();
}
2、编写该接口的实现类
public class SellServiceImpl implements SellService {
@Override
public void sellAirConditioner() {
System.out.println("我卖的是格力空调,请大家赶快来购买,有88折优惠。");
}
}
3、编写一个代理类CgLibFactory,实现接口MethodInterceptor
public class CgLibFactory implements MethodInterceptor {
private Object target;
public CgLibFactory(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 o, Method method, Object[] objects, MethodProxy methodProxy)
throws Throwable {
System.out.println("CGLIB拦截开始啦");
Object obj = method.invoke(target,objects);
System.out.println("CGLIB拦截结束啦");
return obj;
}
}
4、编写一个测试类
public class CglibTest {
public static void main(String[] args) {
SellService sellService = new SellServiceImpl();
SellService ss = (SellService)new CgLibFactory(sellService).getProxyInstance();
ss.sellAirConditioner();
}
}
5、执行结果
CGLIB类的代码示例:
1、编写一个Work类,写一个实现方法handle
public class Work {
void handle() {
System.out.println("因为疫情,我在家里工作。");
}
}
2、编写一个代理类WorkProxy,在里边做一些代码增强
public class WorkProxy implements MethodInterceptor {
Object targetObject;
public WorkProxy(Object targetObject) {
this.targetObject = targetObject;
}
public Object getProxyInstance() {
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(targetObject.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
throws Throwable {
System.out.println("进行正式工作前的准备,喝水");
Object oo = method.invoke(targetObject,objects);
System.out.println("结束工作了,我要下班了");
return oo;
}
}
3、编写一个测试类WorkTest
public class WorkTest {
public static void main(String[] args) {
Work work = new Work();
WorkProxy proxy = new WorkProxy(work);
Work ww = (Work)proxy.getProxyInstance();
ww.handle();
}
}
4、测试结果
参考文档: