Spring中的代理方式 -- JDK动态代理

Spring中的代理方式 – JDK动态代理

什么是动态代理?

使用JDK的反射机制,创建对象的能力,创建的是代理类的对象。而不需要自己去创建类文件,不用创建.java文件。

动态:指的是在程序运行时,动态通过JDK提供的方法去通过反射机制动态创建代理类的对象。

被代理类:需要对某个方法进行增强的类

加强:抽取出公共方法的类

代理类:加强方法后的类

为什么要使用动态代理方式?

可以在不改变原来目标方法功能的前提下,可以在代理中增强自己的功能代码。

这就叫好比是一辆崭新的汽车。原本在汽车出厂的时候已经提供了一定的配置给到用户。

但是用户还是满足不了自己的需求,那怎么办呢?只能是开去改装厂进行功能加装。记住,是加装!!!

在程序中就是不改变原有代码的方式上进行功能的增强,尽量的降低代码之间的耦合性,在Spring中就是通过这样的方式去实现代码的低侵入。

使用JDK动态代理的前提:需要目标我实现接口。

因为在执行调用代理方法的时候需要通过反射的方式去入参一个接口。所以被代理类需要实现接口才能使用JDK动态代理。如果该被代理类没有实现接口,则需要去通过CgLib的方式去通过继承该目标被代理类去实现动态代理的效果。


实现步骤:

1、需要提供一个接口

public interface UserDao {
          
   
    void findUser();
}

2、创建一个实现该接口的实现类

public class UserDaoImpl implements UserDao{
          
   
    @Override
    public void findUser() {
          
   
        //业务代码
        System.out.println("--------UserDaoImpl-------");
    }
}

但是当后续业务需要迭代升级维护的时候,假设需要进行日志记录,但是又不想去该变以前的业务代码,那么就可以用动态代理的方式进行方法的增强

3、创建代理类并实现InvocationHandler接口重写invoke方法

public class JdkProxy implements InvocationHandler {
          
   

    //需要代理的目标对象
    private Object proxyTargetObject;

    //构造方法
    public JdkProxy(Object proxyTargetObject) {
          
   
        this.proxyTargetObject = proxyTargetObject;
    }


    /**
     * 增强方法
     *
     * @param proxy  被代理类
     * @param method 需要增强的被代理类方法
     * @param args   被代理方法参数
     * @return {@link Object}
     * @throws Throwable throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          
   
        System.out.println("-----开始执行JDK动态代理-----");
        //可以写需要进行日志记录的过程
        //......
        //调用被代理类的方法
        Object invokeResult = method.invoke(this.proxyTargetObject, args);
        return invokeResult;
    }

4、编写测试方法

public static void main(String[] args) {
          
   

        UserDaoImpl userDao = new UserDaoImpl();
        //传入被代理类
        JdkProxy proxy = new JdkProxy(userDao);
        //使用JDK动态代理执行目标方法
        UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(
                userDao.getClass().getClassLoader(),
                userDao.getClass().getInterfaces(),
                proxy);
        //执行代理目标方法
        userDaoProxy.findUser();
    }

5、运行测试方法输出结果

可以看出,在执行目标方法之前我们先去执行了我们增强的业务,再去执行原有相关的业务代码。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xB2zcZyU-1680240506291)(C:Users27692AppDataRoamingTypora ypora-user-imagesimage-20230331131905526.png)]

经验分享 程序员 微信小程序 职场和发展