java动态代理模式

  • Java动态代理模式是Java编程语言中的一种设计模式,它提供了一种在运行时动态创建代理对象的方式。这个模式主要用于实现AOP(面向切面编程)的概念,允许开发者在不修改原有业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理、权限验证等。
    在Java中,动态代理模式主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。Proxy类提供了创建代理对象的方法,而InvocationHandler接口定义了代理对象在调用方法时需要实现的接口。
  • 动态代理模式的实现步骤如下:
  1. 定义一个接口,该接口定义了需要被代理的方法,比如:
public interface GreetingService {
    void greet(String name);
}
  1. 实现该接口的具体业务逻辑类。
public class SimpleGreetingService implements GreetingService{
    @Override
    public void greet(String name) {
        System.out.println("Hello,"+name+"!");
    }
}
  1. 创建一个实现了InvocationHandler接口的类,该类负责处理代理对象的方法调用。在这个类中,可以添加额外的功能,如日志记录、事务管理等。
public class LoggingInvocationhandler implements InvocationHandler {

    private final Object target;


    public LoggingInvocationhandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //在方法调用前记录日志
        System.out.println("Method: "+ method.getName()+ " is called with arguments: "+ Arrays.toString(args));

        //调用目标对象的方法
        Object result = method.invoke(target, args);
        //在方法调用后记录日志
        System.out.println("Method "+ method.getName()+" is executed");
        return result;
    }
}
  1. 使用Proxy类的静态方法newProxyInstance()创建代理对象。该方法需要三个参数:被代理类的类加载器、被代理类实现的接口数组、实现了InvocationHandler接口的实例。通过代理对象调用方法时,会调用InvocationHandler接口中的invoke()方法。在该方法中,可以添加额外的功能,然后调用被代理对象的方法。
import java.lang.reflect.Proxy;

public class DynamicProxyExample {
    public static void main(String[] args) {
        //创建目标对象
        SimpleGreetingService greetingService = new SimpleGreetingService();
        //创建InvocationHandler对象
        LoggingInvocationhandler handler = new LoggingInvocationhandler(greetingService);

        //创建代理对象
        GreetingService proxy = (GreetingService) Proxy.newProxyInstance(
                handler.getClass().getClassLoader(),
                greetingService.getClass().getInterfaces(),
                handler);

        //调用代理对象的方法,实际上会调用InvocationHandler的invoke方法
        proxy.greet("World");
    }
}

动态代理模式的优点是可以在运行时动态创建代理对象,而不需要提前编写代理类的代码。这使得开发者可以更加灵活地实现AOP的概念,提高了代码的可维护性和可扩展性。

  • 在Java中,动态代理模式是基于接口的。这意味着你不能直接为一个没有接口的类创建动态代理。动态代理是通过在运行时生成一个新的类来实现的,这个新类实现了你指定的接口,并且将所有方法调用委托给一个InvocationHandler实例。
    具体来说,当你使用Proxy.newProxyInstance()方法创建一个代理对象时,你需要提供一个接口数组作为参数之一。这个数组中的接口定义了代理对象需要实现的方法。因此,如果没有接口,动态代理就无法工作。
    如果你有一个没有实现任何接口的类,并且想要为它创建代理,那么你不能使用Java标准库中的动态代理模式。在这种情况下,你可能需要使用其他技术或库,如CGLIB。CGLIB是一个强大的高性能的代码生成库,它可以在运行时扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的拦截。
    总结一下,"动态代理模式只能用于接口,不能用于类"这句话的意思是:在Java中,你不能直接为没有实现接口的类创建动态代理。如果你需要为一个类创建代理,你可能需要使用其他技术或库,如CGLIB。

补充:案例2
首先,定义一个接口及其实现类:

// 定义一个接口
public interface GreetingService {
    String sayHello(String name);
}

// 实现接口的类
public class GreetingServiceImpl implements GreetingService {
    @Override
    public String sayHello(String name) {
        return "Hello, " + name + "!";
    }
}
接着,创建一个实现了InvocationHandler接口的类,用于处理代理实例上的方法调用并定义横切逻辑(如日志记录、事务管理等):

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

public class GreetingServiceProxyHandler implements InvocationHandler {
    // 目标对象,被代理的对象
    private Object target;

    public GreetingServiceProxyHandler(Object target) {
        this.target = target;
    }

    // 实现invoke方法,处理代理实例上的方法调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 可以在这里添加前置通知(如日志记录)
        System.out.println("Before method " + method.getName() + " is called");

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

        // 可以在这里添加后置通知(如日志记录)
        System.out.println("After method " + method.getName() + " is called");

        return result;
    }

    // 静态方法,用于创建代理对象
    public static Object createProxy(Object target) {
        // 获取目标对象的类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        // 获取目标对象实现的接口
        Class<?>[] interfaces = target.getClass().getInterfaces();
        // 创建代理对象
        return Proxy.newProxyInstance(classLoader, interfaces, new GreetingServiceProxyHandler(target));
    }
}
最后,编写客户端代码来测试动态代理:

java
public class DynamicProxyDemo {
    public static void main(String[] args) {
        // 创建目标对象
        GreetingService greetingService = new GreetingServiceImpl();
        
        // 创建代理对象
        GreetingService proxy = (GreetingService) GreetingServiceProxyHandler.createProxy(greetingService);
        
        // 通过代理对象调用方法
        String message = proxy.sayHello("Alice");
        
        // 输出结果
        System.out.println(message);
    }
}

在这个案例中,GreetingService 接口定义了一个 sayHello 方法,GreetingServiceImpl 类实现了这个方法。GreetingServiceProxyHandler 类实现了 InvocationHandler 接口,并重写了 invoke 方法来定义代理的行为。在 invoke 方法中,我们在调用目标方法前后添加了日志记录。

createProxy 方法是一个静态工厂方法,它使用 Proxy.newProxyInstance 方法来创建代理对象。这个方法需要三个参数:类加载器、接口数组和 InvocationHandler 实例。

在 main 方法中,我们创建了目标对象 greetingService,然后使用 GreetingServiceProxyHandler.createProxy 方法创建了它的代理对象 proxy。最后,我们通过代理对象调用 sayHello 方法,并输出返回的字符串。

运行这个案例,你将看到控制台输出类似以下内容:

Before method sayHello is called
Hello, Alice!
After method sayHello is called

posted @ 2024-04-19 09:39  文采杰出  阅读(12)  评论(0编辑  收藏  举报