Spring5 代理设计模式的实现原理
Posted 冰点IT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring5 代理设计模式的实现原理相关的知识,希望对你有一定的参考价值。
一、什么是代理设计模式
代理设计模式:为其他对象提供一种代理来控制这个对象的访问,比如:公司现在要去谈一个业务,这个业务的核心功能都是由A员工负责的,但是A不想去接触一些与核心功能无关的事情,所以就将一些辅助工作交由B员工来做,当具体到核心业务时,由B向A转达完成核心功能,那么B就是A的代理。代理又分为静态代理和动态代理,静态代理和动态代理最大的区别是静态代理的代理对象在做事前是已知的,动态代理的代理对象是在做事前动态创建的,废话不说了,下面来看代码。
二、静态代理
根据以上的论述,静态代理就是在谈业务时已经找好了A员工的代理B,直接披挂上阵即可。
1、创建接口UserService.java
public interface UserService {
/**
* 保存用户信息
* @return
*/
public Boolean insertUser();
/**
* 根据id查询用户名
* @param id
* @return
*/
public String queryUserNameById(Long id);
}
2、创建实现类UserServiceImpl.java
public class UserServiceImpl implements UserService{
public Boolean insertUser() {
return true;
}
public String queryUserNameById(Long id) {
//用户数据模拟
Map<Long, String> userNameMap = new HashMap<>();
userNameMap.put(1l, "张三");
userNameMap.put(2l, "李四");
userNameMap.put(3l, "王五");
return userNameMap.get(id);
}
}
3、创建UserServiceImpl的代理类
public class UserServiceImplStaticProxy implements UserService {
private UserServiceImpl targetObj = new UserServiceImpl();
public Boolean insertUser() {
System.out.println("******代理**********开启事务****************");
boolean flag = targetObj.insertUser();
System.out.println("******代理**********提交事务****************");
return flag;
}
public String queryUserNameById(Long id) {
return targetObj.queryUserNameById(id);
}
}
4、创建静态代理测试类
public class TestProxy {
/**
* 测试静态代理
*/
@Test
public void testStaticProxy() {
UserServiceImplStaticProxy userServiceImplStaticProxy = new UserServiceImplStaticProxy();
Boolean flag = userServiceImplStaticProxy.insertUser();
if(flag) {
System.out.println("用户新增成功!");
} else {
System.out.println("用户新增失败!");
}
System.out.println("*************************静态代理分割线*******************************");
String userName = userServiceImplStaticProxy.queryUserNameById(1l);
System.out.println("id为1的用户名称为:" + userName);
}
}
5、运行测试结果
******代理**********开启事务****************
******代理**********提交事务****************
用户新增成功!
*************************静态代理分割线*******************************
id为1的用户名称为:张三
由运行结果可知静态代理对象已经可以正常完成辅助业务了(事务开启与关闭)。
三、动态代理基于JDK
1、创建基于JDK的代理工厂
public class ProxyFactoryBaseJdk {
private Object target;
public ProxyFactoryBaseJdk(Object target) {
this.target = target;
}
/**
* 获取代理对象
* @return
*/
public Object getProxyInstance() {
Class clazz = target.getClass();
Object proxy = Proxy.newProxyInstance(
clazz.getClassLoader(), //获取目标类的类加载器
clazz.getInterfaces(), //获取目标类所实现的所有接口
new InvocationHandler() //执行代理对象方法时触发
{
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行结果
Object result = null;
//如果是新增需要处理事务
if(method.getName().equals("insertUser")) {
System.out.println("******代理**********开启事务****************");
result = method.invoke(target, args);
System.out.println("******代理**********提交事务****************");
} else {
//直接执行
result = method.invoke(target, args);
}
return result;
}
});
return proxy;
}
}
6、创建基于JDK动态代理测试类
public class TestProxy {
@Test
public void testJdkAutoProxy() {
UserServiceImpl userServiceImpl = new UserServiceImpl();
ProxyFactoryBaseJdk factoryBaseJdk = new ProxyFactoryBaseJdk(userServiceImpl);
UserService userServiceProxy = (UserService)factoryBaseJdk.getProxyInstance();
Boolean flag = userServiceProxy.insertUser();
if(flag) {
System.out.println("用户新增成功!");
} else {
System.out.println("用户新增失败!");
}
System.out.println("*************************Jdk动态代理分割线*******************************");
String userName = userServiceProxy.queryUserNameById(1l);
System.out.println("id为1的用户名称为:" + userName);
}
}
7、运行JDK动态代理测试结果
******代理**********开启事务****************
******代理**********提交事务****************
用户新增成功!
*************************Jdk动态代理分割线*******************************
id为1的用户名称为:张三
由运行结果可知基于JDK的动态代理也能够正常的完成辅助业务了(事务的创建与提交)。
四、动态代理基于CGLIB
1、创建ArticleService.java
public class ArticleService {
/**
* 插入文章
* @return
*/
public Boolean insertArticle() {
return true;
}
/**
* 根据文章ID获取文章名称
* @param id
* @return
*/
public String queryArticleNameById(Long id) {
//文章数据模拟
Map<Long, String> articleNameMap = new HashMap<>();
articleNameMap.put(1l, "Spring 实战");
articleNameMap.put(2l, "Spring boot 实战");
articleNameMap.put(3l, "Spring cloud 实战");
return articleNameMap.get(id);
}
}
8、创建ArticleService方法拦截器
public class ArticleServiceMethodInterceptor implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//执行结果
Object result = null;
//如果是新增需要处理事务
if(method.getName().equals("insertArticle")) {
System.out.println("******代理**********开启事务****************");
result = methodProxy.invokeSuper(o, objects);
System.out.println("******代理**********提交事务****************");
} else {
//直接执行
result = methodProxy.invokeSuper(o, objects);
}
return result;
}
}
9、创建基于CGLIB的动态代理测试类
public class TestProxy {
@Test
public void testCGLIBAutoProxy() {
ArticleService articleService = new ArticleService();
ProxyFactoryBaseCGLIB proxyFactoryBaseCGLIB = new ProxyFactoryBaseCGLIB(articleService);
ArticleService ArticleServiceProxy = (ArticleService)proxyFactoryBaseCGLIB.getProxyInstance();
Boolean flag = ArticleServiceProxy.insertArticle();
if(flag) {
System.out.println("文章新增成功!");
} else {
System.out.println("文章新增失败!");
}
System.out.println("*************************CGLIB动态代理分割线*******************************");
String articleName = ArticleServiceProxy.queryArticleNameById(1l);
System.out.println("id为1的文章名称为:" + articleName);
}
}
10、运行测试结果
******代理**********开启事务****************
******代理**********提交事务****************
文章新增成功!
*************************CGLIB动态代理分割线*******************************
id为1的文章名称为:Spring 实战
由运行结果可知基于CGLIB的动态代理也能够正常的完成辅助业务了(事务的创建与提交)。
总结一下:
通过以上两种不同的动态代理实现方式,我们很容易发现,其实最大的区别在于基于JDK的动态代理,委托类必须要实现一个接口,JDK动态代理会根据此接口创建一个代理实现类来完成代理业务。
而基于CGLIB的动态代理,委托类不需要实现接口,CGLIB动态代理会根据委托类创建一个子类,由子类完成代理业务,那么不管是动态代理还是静态代理对外貌似代理对象完成了所有的业务,实际上代理对象只完成的是辅助业务核心业务还是由委托类对象完成,Spring的动态代理以上两种方式都支持,只需要配置一下下即可,配置参考之前的文章。
关注我↓↓↓
您的关注是对我最大的鼓励!
逛逛我的星球呗↓↓↓
以上是关于Spring5 代理设计模式的实现原理的主要内容,如果未能解决你的问题,请参考以下文章