目录
1.核心本质
在不改动原有代码的情况下,进行逻辑的增加。
2.静态代理
每个都需要手动生成一个代理类,繁琐,耦合度高(动态代理优化)
2.1 数字藏品举例
2.1.1 售卖接口
/**
* 售卖
*/
public interface Sale {
void digitalSale();
}
2.1.2 数字藏品所有者
/**
* 代表数字藏品主人
*/
public class DigitalcCllectiblesMaster implements Sale{
@Override
public void digitalSale() {
System.out.println("数字藏品销售");
}
}
2.1.3 数字平台售卖
/**
* 代理平台
*/
public class ProxyPlatform implements Sale{
private DigitalcCllectiblesMaster master;
public ProxyPlatform(){
}
public ProxyPlatform(DigitalcCllectiblesMaster master) {
this.master = master;
}
@Override
public void digitalSale() {
System.out.println("代理平台销售");
master.digitalSale();
}
public void digitalSaleMore(){
System.out.println("代理平台查看更多样式");
}
public void pay(){
System.out.println("代理平台支付");
}
}
2.1.4 测试类
public class Test {
public static void main(String[] args) {
//最开始不用平台代理,直接1对1售卖
DigitalcCllectiblesMaster digitalcCllectiblesMaster = new DigitalcCllectiblesMaster();
digitalcCllectiblesMaster.digitalSale();
System.out.println("------------------------------------");
//通过平台代理
DigitalcCllectiblesMaster digitalcCllectiblesMaster1 = new DigitalcCllectiblesMaster();
ProxyPlatform proxyPlatform = new ProxyPlatform(digitalcCllectiblesMaster1);
proxyPlatform.digitalSale();
//代理可以在不修改代码的情况下,增加一些额外的功能 此处体现就是 原来的1对1售卖,现在变成了平台售卖 平台可以收取手续费 可以选购其他的 也就是附属操作
proxyPlatform.pay();
proxyPlatform.digitalSaleMore();
}
}
2.2 CRUD例子
2.2.1 controller层
/**
* 控制层调用Service层
*/
public class CrudController {
private CrudService crudService;
public CrudController(CrudService crudService) {
this.crudService = crudService;
}
public void add() {
System.out.println("controller新增");
crudService.add();
}
public void update() {
System.out.println("controller修改");
crudService.update();
}
public void delete() {
System.out.println("controller删除");
crudService.delete();
}
public void select() {
System.out.println("controller查询");
crudService.select();
}
}
2.2.2 service 接口和实现
public interface CrudService {
void add();
void delete();
void update();
void select();
}
/**
* 我们需要在数据库执行前 查看数据打印情况 不使用代理需要改原有代码 并且如果有多个方法 需要增加很多代码
* 我们可以使用代理类解决
*/
public class CrudServiceImpl implements CrudService{
private CrudMapperImplProxy crudMapperImplProxy;
public CrudServiceImpl(CrudMapperImplProxy crudMapperImplProxy) {
this.crudMapperImplProxy = crudMapperImplProxy;
}
@Override
public void add() {
crudMapperImplProxy.add();
}
@Override
public void delete() {
crudMapperImplProxy.delete();
}
@Override
public void update() {
crudMapperImplProxy.update();
}
@Override
public void select() {
crudMapperImplProxy.add();
}
}
2.2.3 mapper 接口和实现
public interface CrudMapper {
void add();
void delete();
void update();
void select();
}
public class CrudMapperImpl implements CrudMapper{
@Override
public void add() {
System.out.println("添加数据");
}
@Override
public void delete() {
System.out.println("删除数据");
}
@Override
public void update() {
System.out.println("更新数据");
}
@Override
public void select() {
System.out.println("查询数据");
}
}
2.2.4 mapper代理类
public class CrudMapperImplProxy implements CrudMapper{
private CrudMapperImpl crudMapperImpl;
public CrudMapperImplProxy(CrudMapperImpl crudMapperImpl) {
this.crudMapperImpl = crudMapperImpl;
}
@Override
public void add() {
log("add方法执行前");
crudMapperImpl.add();
}
@Override
public void delete() {
log("delete方法执行前");
crudMapperImpl.delete();
}
@Override
public void update() {
log("update方法执行前");
crudMapperImpl.update();
}
@Override
public void select() {
log("select方法执行前");
crudMapperImpl.select();
}
public void log(String msg){
System.out.println(msg+"执行数据为===");
}
}
2.2.5 测试类
public class Test {
public static void main(String[] args) {
CrudController crudController = new CrudController(new CrudServiceImpl(new CrudMapperImplProxy(new CrudMapperImpl())));
crudController.add();
}
}
3.动态代理
3.1 动态代理的分类
1.jdk动态代理(举例为jdk)
2.cglib动态代理
3.基于字节码的动态代理:javasist
3.2 动态代理的优点
减少重复代码: 动态代理可以在运行时生成代理类,从而避免编写大量重复的代理类代码。这样可以减少代码量,提高代码的可维护性和可读性。
统一处理逻辑: 可以在代理类中统一处理额外的逻辑,例如日志记录、性能监控、事务管理等。这些逻辑可以集中在代理类中实现,而不需要分散到多个实际的业务类中去。
解耦合: 动态代理可以将实际的业务逻辑和横切关注点(cross-cutting concerns)分离开来。业务类专注于核心业务逻辑,而代理类则处理通用的横切关注点,从而实现了高内聚、低耦合的设计。
灵活性: 动态代理可以根据需要动态创建代理对象,不需要预先知道所有的被代理类。这种灵活性使得动态代理适用于各种不同的场景和需求。
扩展性: 由于动态代理可以通过编程的方式生成代理类,因此可以根据实际需求定制不同的代理类。这种灵活性和扩展性使得动态代理在软件设计中具有重要的地位和作用。
3.3 藏品的动态代理类
使用静态代理的固定类
3.3.1 动态代理类
public class ProxyInvocationHandle implements InvocationHandler {
//被代理的接口
private Sale sale;
public void setSale(Sale sale){
this.sale=sale;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),sale.getClass().getInterfaces(),this);
}
//处理代理实例
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(sale, args);
return invoke;
}
}
3.3.2 测试类
public class Test {
public static void main(String[] args) {
//真实角色
DigitalcCllectiblesMaster digitalcCllectiblesMaster = new DigitalcCllectiblesMaster();
//代理过程,处理程序
ProxyInvocationHandle proxyInvocationHandle = new ProxyInvocationHandle();
proxyInvocationHandle.setSale(digitalcCllectiblesMaster);
//代理对象
Sale sale = (Sale) proxyInvocationHandle.getProxy();
sale.digitalSale();
}
}
3.4 mapper动态代理类(万能代理)
3.4.1 万能代理类
public class ProxyInvocationHandler implements InvocationHandler {
private Object object;
public void setObject(Object o){
this.object=o;
}
public Object getProxyObject(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeLog(method.getName());
Object invoke = method.invoke(object, args);
afterLog(method.getName());
return invoke;
}
public void beforeLog(String s){
System.out.println(s+"sql开始执行"+new Date());
}
public void afterLog(String s){
System.out.println(s+"sql开始执行"+new Date());
}
}
3.4.2 测试类
public class Test {
public static void main(String[] args) {
CrudMapperImpl crudMapper = new CrudMapperImpl();
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
proxyInvocationHandler.setObject(crudMapper);
CrudMapper crudMapper1 = (CrudMapper) proxyInvocationHandler.getProxyObject();
crudMapper1.update();
}
}
4.动态代理(cglib)
使用静态代理的固定类
4.1 拦截器
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 需要cglib依赖 自己手动添加
*/
import java.lang.reflect.Method;
import java.util.Date;
public class CglibInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
beforeLog();
Object o1 = methodProxy.invokeSuper(o, objects);
afterLog();
return o1;
}
public void beforeLog(){
System.out.println("sql开始执行"+new Date());
}
public void afterLog(){
System.out.println("sql开始执行"+new Date());
}
}
4.2 客户端
import net.sf.cglib.proxy.Enhancer;
import shejimoshi.structural.a_proxy.dynamicProxy.demo02.CrudMapperImpl;
/**
* 需要cglib依赖 自己手动添加
*/
public class Test {
public static void main(String[] args) {
CglibInterceptor cglibInterceptor = new CglibInterceptor();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CrudMapperImpl.class);
enhancer.setCallback(cglibInterceptor);
CrudMapper crudMapper = (CrudMapper) enhancer.create();
crudMapper.add();
}
}
5.JDK和CGLIB的区别
代理类型 | 实现机制 | 回调方式 | 使用场景 | 效率 |
JDK | 通过实现接口,通过反射机制获取接口里的方法,实现InvocationHandler接口,实现方法拦截,自定义Proxy.newProxyInstance()方法,以及invoke方法 | 调用invoke方法,代理类内部如果自定了proxy可以直接调用 | 目标类有实现接口 | 1.8高于cgilb |
CGLIB | 通过继承去实现,代理方法实现MethodsInterceptor调用父类的目标方法,在intercept方法内部自定义增强方法 | 调用intercept方法 | 没有被final修饰的类 | 第一次调用慢,因为要生成字节码,多次调用效率高 |