动态代理就是面向切面?

  • Post author:
  • Post category:其他


现在有一个非常流行的名称叫做

面向横切面编程

,也就是AOP(Aspect Oriented Programming),其核心就是采用了动态代理机制,既然这么重要,我们就来看看动 态代理是如何实现的

先上代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义接口
interface UserService {
    void save(String username);
}

// 实现接口的类
class UserServiceImpl implements UserService {
    @Override
    public void save(String username) {
        System.out.println("保存用户: " + username);
    }
}



class UserServiceProxy implements InvocationHandler {
    private final UserService target;

    public UserServiceProxy(UserService target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在方法调用前执行额外的逻辑
        System.out.println("Before method: " + method.getName());

        // 调用目标对象的方法
        Object result = method.invoke(target, args);

        // 在方法调用后执行额外的逻辑
        System.out.println("After method: " + method.getName());

        return result;
    }


}



public class DynamicProxyDemo {
    public static void main(String[] args) {
        // 创建目标对象
        UserService userService = new UserServiceImpl();

        // 创建代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
                UserService.class.getClassLoader(),
                new Class<?>[] { UserService.class },
                new UserServiceProxy(userService)
        );

        // 调用代理对象的方法
        proxy.save("Alice");
    }
}

输出:

Before method: save

保存用户: Alice

After method: save

这段代码使用了

Proxy.newProxyInstance( UserService.class.getClassLoader(), new Class<?>[] { UserService.class }, new UserServiceProxy(userService) )

方法来创建一个代理对象,以下是每个参数的解释:


  1. UserService.class.getClassLoader()

    :这是第一个参数,它指定了代理类的类加载器。在这里,

    我们使用了

    UserService

    类的类加载器来加载代理类

    。这确保了代理类与目标接口 (

    UserService

    ) 在同一个类加载器中。


  2. new Class<?>[] { UserService.class }

    :这是第二个参数,它是一个接口数组,


    表示代理类需要实现的接口(



    注意是实现所有接口



    )


    。在这里,我们只有一个接口

    UserService

    ,因此传递了一个包含该接口的数组。


  3. new UserServiceProxy(userService)

    :这是第三个参数,它是一个

    InvocationHandler

    类型的对象,用于处理代理对象上的方法调用。在这里,我们创建了一个

    UserServiceProxy

    的实例,

    该代理会在调用代理对象上的方法时执行

    UserServiceProxy

    中定义的逻辑

所以,这段代码的目的是创建一个代理对象,这个代理对象实现了

UserService

接口,并且在调用

UserService

接口中的方法时,会委派给

UserServiceProxy

中的

invoke

方法来执行额外的逻辑,如在方法调用前后打印日志等。

这样,我们可以在不修改原始

UserService

实现的情况下,添加额外的行为或功能。


但是以上代码有个问题:


需要为每个接口都创建一个独立的代理类,不够灵活

。所以可以使用Java的动态代理与反射机制来实现一个通用的代理类,而不需要为每个接口都编写一个特定的代理类。

上代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义接口
interface UserService {
    void save(String username);
}

// 实现接口的类
class UserServiceImpl implements UserService {
    @Override
    public void save(String username) {
        System.out.println("保存用户: " + username);
    }
}


class GenericProxy<T> implements InvocationHandler {
    private T target;

    public GenericProxy(T target) {
        this.target = target;
    }

    @SuppressWarnings("unchecked")
    public static <T> T createProxy(T target) {
        return (T) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new GenericProxy<>(target)
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在方法调用前执行额外的逻辑
        System.out.println("Before method: " + method.getName());

        // 调用目标对象的方法
        Object result = method.invoke(target, args);

        // 在方法调用后执行额外的逻辑
        System.out.println("After method: " + method.getName());

        return result;
    }
}


public class DynamicProxyDemo {
    public static void main(String[] args) {
        // 创建目标对象
        UserService userService = new UserServiceImpl();

        // 创建代理对象,不再需要为每个接口编写特定的代理类
        UserService proxy = GenericProxy.createProxy(userService);

        // 调用代理对象的方法
        proxy.save("Alice");
    }
}

输出:

Before method: save

保存用户: Alice

After method: save

这种方式可以更灵活地创建代理对象,无需为每个接口都创建一个独立的代理类,从而提高了代码的可维护性和可扩展性。



版权声明:本文为liuruiaaa原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。