动态代理就是面向切面?

        现在有一个非常流行的名称叫做面向横切面编程,也就是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 implements InvocationHandler {
    private T target;

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

    @SuppressWarnings("unchecked")
    public static  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

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

你可能感兴趣的:(设计模式,java,开发语言)