什么是代理

代理是对某个类或者某个接口方法进行增强的一种手段,说直白一点就是在不改变其内部结构和代码的基础上对该代码进行扩展

实现方式

静态代理

简单的增强。每次扩展都是自己手动写代理类,假设我们有个新增用户的接口

  1. public class UserService {
  2. public void doSaveUser(){
  3. System.out.println("开始UserService保存操作");
  4. }
  5. }
  1. 新增代理对象
  1. public class UserServiceProxy {
  2. private UserService userService;
  3. public void doSave() {
  4. System.out.println("代理前置方法");
  5. userService.doSaveUser();
  6. System.out.println("代理后置方法");
  7. }
  8. public UserServiceProxy(UserService userService) {
  9. this.userService = userService;
  10. }
  11. }

测试一下

  1. public class DemoMain {
  2. public static void main(String[] args) {
  3. UserServiceProxy userServiceProxy = new UserServiceProxy(new UserService());
  4. userServiceProxy.doSave();
  5. }
  6. }

image.png
静态代理是最简单也是最好理解的代理模式

动态代理

什么是动态代理

顾明思意,使用动态的方式进行代理,不需要同静态代理一般每次都新增代理对象

jdk的动态代理

  1. // 接口
  2. public interface IUserService {
  3. void saveUser();
  4. }
  1. // 实现
  2. public class UserServiceImpl implements IUserService{
  3. @Override
  4. public void saveUser() {
  5. System.out.println("接口形式动态代理方法执行。。。。。");
  6. }
  7. }
  1. // 动态代理类
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. public class JdkUserProxy implements InvocationHandler {
  5. // 这其实业务实现类对象,用来调用具体的业务方法
  6. private Object target;
  7. // 通过构造函数传入目标对象
  8. public JdkUserProxy(Object target) {
  9. this.target = target;
  10. }
  11. @Override
  12. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  13. System.out.println("代理前。。。。。。。");
  14. Object result = method.invoke(target, args);
  15. System.out.println("代理后。。。。。。。");
  16. return result;
  17. }
  18. }
  1. // 测试
  2. public static void main(String[] args) {
  3. IUserService userService = new UserServiceImpl();
  4. InvocationHandler jdkUserProxy = new JdkUserProxy(userService);
  5. IUserService userService1 = (IUserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), jdkUserProxy);
  6. userService1.saveUser();
  7. }
  8. 注意:包引用,因为和cglib一起在做测试,所以可能会引入成cglibProxy对象,一定是java.lang.reflect.*下的东西

image.png正常运行
问题:debug模式F8走一步会代理类执行一次,有点没想明白(网上说idea会有这个问题,而且这个问题无解)
image.png

Cglib动态代理

引入cglib坐标,当然简单java工程把jar导入即可

  1. <dependency>
  2. <groupId>cglib</groupId>
  3. <artifactId>cglib</artifactId>
  4. <version>3.3.0</version>
  5. </dependency>

还是之前的UserService

  1. public class UserService {
  2. public void doSaveUser(){
  3. System.out.println("开始UserService保存操作");
  4. }
  5. }

创建代理类,实现MethodInterceptor接口,重写拦截方法

  1. public class UserServiceCglibProxy implements MethodInterceptor {
  2. @Override
  3. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  4. System.out.println("代理前。。。。。。。");
  5. Object invoke = methodProxy.invokeSuper(o, objects);
  6. System.out.println("代理后。。。。。。。");
  7. return invoke;
  8. }
  9. }

使用Enhancer 动态创建实例,设置SuperClass和Callback,个人理解是将需要代理的对象和代理类绑定,然后根据父类创建出子类,实际执行是这个子类在调用方法

  1. public static void main(String[] args) {
  2. Enhancer enhancer =new Enhancer();
  3. enhancer.setSuperclass(UserService.class);
  4. enhancer.setCallback(new UserServiceCglibProxy());
  5. UserService userService=(UserService)enhancer.create();
  6. userService.doSaveUser();
  7. }

结果
image.png

这只是简单的一个Demo实现,还有很多需要深入挖掘的地方,使用场景因人而异,接口增加功能可以用,日志等也可以用,当然不用这些花里胡哨的东西也能写代码,我们需要成为代码创造者,而不是代码搬运工