一、代理概念
在某种情况下,客户类不能直接引用目标对象,需要通过代理对象去引用。一般的代理模式都会有一个接口,代理对象和目标对象共同实现这个接口。静态代理(继承,实现接口)和动态代理(基于接口的jdk动态代理,不基于接口的cglib动态代理)。
二、代理模式
手机销售案例,手机买卖都需要记录日志。
业务接口类
package com.aaa.reflectDemo.proxy.staticProxy;
public interface PhoneService {
void buyPhone(int num);
void salePhone(int num);
}
业务实现类
package com.aaa.reflectDemo.proxy.staticProxy;
public class PhoneServiceImpl implements PhoneService{
@Override
public void buyPhone(int num) {
System.out.println("业务:手机进货"+num+"部");
}
@Override
public void salePhone(int num) {
System.out.println("业务:手机销售"+num+"部");
}
}
日志工具类
package com.aaa.reflectDemo.proxy.util;
import java.util.Date;
public class LogUtil {
public void log(String method) {
System.out.println(method + "被调用了" + new Date());
}
}
2.1 静态代理
2.1.1 基于接口的静态代理
package com.aaa.reflectDemo.proxy.staticProxy;
import com.aaa.reflectDemo.proxy.util.LogUtil;
public class ProxyStaticInterface implements PhoneService{
LogUtil logUtil = new LogUtil();
@Override
public void buyPhone(int num) {
System.out.println("业务:进了"+num+"部手机");
logUtil.log("buyPhone");
}
@Override
public void salePhone(int num) {
System.out.println("业务:进了"+num+"部手机");
logUtil.log("salePhone");
}
public static void main(String[] args) {
//获取目标对象
// PhoneService phoneService = new PhoneServiceImpl();
// phoneService.buyPhone(200);
//获取代理对象
PhoneService phoneService= new ProxyStaticInterface();
phoneService.buyPhone(300);
phoneService.salePhone(100);
}
}
打印结果:
2.1.2 基于继承的静态代理
package com.aaa.reflectDemo.proxy.staticProxy;
import com.aaa.reflectDemo.proxy.util.LogUtil;
public class ProxyStaticExtends extends PhoneServiceImpl {
LogUtil logUtil = new LogUtil();
@Override
public void buyPhone(int num) {
super.buyPhone(num);
logUtil.log("buyPhone");
}
@Override
public void salePhone(int num) {
super.salePhone(num);
logUtil.log("salePhone");
}
public static void main(String[] args) {
//获取目标对象
// PhoneService phoneService = new PhoneServiceImpl();
// phoneService.buyPhone(200);
//获取代理对象
PhoneServiceImpl phoneService= new ProxyStaticExtends();
phoneService.buyPhone(300);
phoneService.salePhone(100);
}
}
测试结果
缺点:每一个目标对象,都需要匹配一个代理类,并且目标对象方法变更,代理类必须同步更新。
目标对象:具体的业务
代理对象:执行的过程中真正运行的对象。
2.2 动态代理
业务接口类
package com.aaa.reflectDemo.proxy.dynamicProxy_jdk;
public interface ComputerService {
void buyComputer(int num);
}
业务实现类
package com.aaa.reflectDemo.proxy.dynamicProxy_jdk;
public class ComputerServiceImpl implements ComputerService {
@Override
public void buyComputer(int num) {
System.out.println("成功购买"+num+"台");
}
}
2.2.1 基于接口的jdk动态代理
必须实现接口InvocationHandler(调用处理器)
package com.aaa.reflectDemo.proxy.dynamicProxy_jdk;
import com.aaa.reflectDemo.proxy.util.LogUtil;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
/**
* @author :caicai
* @date :Created in 2022/6/14 17:00
* @description:基于接口的jdk动态代理 必须实现接口 InvocationHandler(调用处理器)
* @modified By:
* @version:
*
* InvocationHandler是由代理实例的调用处理程序实现的接口
*/
public class ProxyDynamicInterface implements InvocationHandler {
// 声明目标对象
private Object targetObj;
LogUtil logUtil = new LogUtil();
/**
* @description: 传入目标对象,获取代理对象
* @create time: 2022/6/14 15:28
* @param target 目标对象
* @return
*/
public Object getProxyObj(Object target){
/**
* 构建代理对象
* newProxyInstance 三个参数
* * @param loader the class loader to define the proxy class
* * @param interfaces the list of interfaces for the proxy class to implement(当前对象实现的那些接口)
* * @param h the invocation handler to dispatch method invocations to 处理器
*
* Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类
*/
targetObj = target;
Object proxyInstance = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return proxyInstance;
}
/**
* 处理代理实例上的方法调用并返回结果。
* @param proxy 代理对象
* @param method 方法
* @param args 包含的方法调用传递代理实例的参数值
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 此处书写增强处理的代码,日志处理
System.out.println("动态代理日志:" + method.getName() + new Date());
// 执行目标对象中的方法
Object invoke = method.invoke(targetObj, args);
return invoke;
}
public static void main(String[] args) {
// 创建目标对象
ComputerServiceImpl computerService = new ComputerServiceImpl();
// 创建代理对象
ProxyDynamicInterface dynamicInterface = new ProxyDynamicInterface();
// 传入目标对象创建代理对象
ComputerService proxyObj = (ComputerService) dynamicInterface.getProxyObj(computerService);
// 代理对象完成任务
proxyObj.buyComputer(800);
}
}
结果打印:
2.2.2 不基于接口的cglib动态代理
CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。spring框架自带cglib。
1、引入cglib的依赖jar
<!-- cglib动态代理jar -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2、创建动态代理工具类
package com.aaa.reflectDemo.proxy.util;
/**
* @author :caicai
* @date :Created in 2022/6/15 9:51
* @description:动态代理接口
* @modified By:
* @version:
*/
public interface ProxyDynamic<T> {
// 获取代理对象
T getProxyObj();
}
基于cglib的动态代理实现类
package com.aaa.reflectDemo.proxy.dynamicProxy_cglib;
import com.aaa.reflectDemo.proxy.dynamicProxy_jdk.ComputerServiceImpl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.Date;
/**
* @author :caicai
* @date :Created in 2022/6/14 17:57
* @description:不基于接口的动态代理工具类(cglib) 需要导入 cglib动态代理jar包
* @modified By:
* @version:
*/
public class ProxyDynamicCGlib {
/**
* @description: 传入目标对象的class类型
* @create time: 2022/6/14 16:36
* @param targetClass
* @return Object
*/
public Object getProxyObj(Class<? extends Object> targetClass){
// 1、定义一个字节码增强器
Enhancer enhancer = new Enhancer();
// 2、设置增强类,目标对象所属类
enhancer.setSuperclass(targetClass);
// 3、给增强设置回掉函数
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 增强处理
System.out.println("动态代理日志:"+method.getName()+new Date());
// 执行目标对象中的方法
Object invokeSuper = proxy.invokeSuper(obj, args);
return invokeSuper;
}
});
// 4、返回增强器
return enhancer.create();
}
public static void main(String[] args) {
//创建代理对象
ProxyDynamicCGlib proxyDynamicCGlib= new ProxyDynamicCGlib();
// 传入目标类 返回代理对象
ComputerServiceImpl proxyObj = (ComputerServiceImpl) proxyDynamicCGlib.getProxyObj(ComputerServiceImpl.class);
proxyObj.buyComputer(300);
}
}
结果打印: