采用动态代理的方式对一个类进行增强

本文介绍了如何通过创建接口和实现类,然后利用动态代理技术对实现类进行功能增强,详细阐述了动态代理调用方法的过程。
  1. 创建一个接口
package com.itheima.proxy;
/*
 * 服务员的接口
 */
public interface Waiter {

    public void server();

    public String sayHello(String name);
}
  1. 创建一个类来实现这个接口
package com.itheima.proxy;
/*
 * 服务员的实现类
 */
public class Waitress implements Waiter {

    @Override
    public void server() {
        System.out.println("服务中......");
    }

    @Override
    public String sayHello(String name) {

        return "Hello" + name;
    }

}
  1. 采用动态代理的方式对这个类进行增强并且调用方法
package com.itheima.proxy;

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

import org.junit.Test;

public class ProxyDemo1 {

    @Test
    public void demo1(){
        Waiter waiter = new Waitress();
        //waiter.server();

        //使用动态地代理:Proxy, newProxyInstance
        /*
         * ClassLoader  :类加载器
         * class[]      :被增强的对象实现的所有接口
         * InvocationHandler  :处理类
         */
        //第一个参数
        ClassLoader classLoader = waiter.getClass().getClassLoader();
        //第二个参数
        Class[] interfaces =  waiter.getClass().getInterfaces();
        //第三个参数
        //相当于Waiter的实现类
        Waiter waiter2 = (Waiter)Proxy.newProxyInstance(classLoader, interfaces, new MyInvocationHandler(waiter) );
        //waiter2.server();
        //说明现在调用代理对象的任何方法的时候,InvocationHandler中的invoke方法执行
        //waiter2.sayHello("张三");
        String s = waiter2.sayHello("李四");
        System.out.println(s);
    }
}

class MyInvocationHandler implements InvocationHandler{
    private Waiter waiter;
    public MyInvocationHandler(Waiter waiter){
        this.waiter = waiter;
    }
    @Override
    /*
     * 方法的参数:
     * proxy   :产生的代理对象
     * method  :当前正在调用的目标类的方法
     * obj     :正在执行的方法中的参数
     * 
     */
    public Object invoke(Object proxy, Method method, Object[] params)
            throws Throwable {
        //System.out.println("InvocationHandler  invocake执行了.....");
        //waiter.server();
        //System.out.println(method.getName());
        //利用反射使特定的方法执行
        Object obj = method.invoke(waiter, params);
        return obj;
    }


}
### Spring框架中JDK动态代理与服务层对象的行为分析 在Spring框架中,当采用JDK动态代理时,服务层对象的代理机制和行为受到事务注解(`@Transactional`)以及AOP配置的影响。以下是关于这一主题的具体解析。 --- #### JDK动态代理的工作原理 JDK动态代理是一种基于接口的代理机制,它通过`java.lang.reflect.Proxy`为实现了一个或多个接口的目标生成代理对象[^1]。代理对象会在运行时拦截对目标方法的调用,并在此过程中应用增强逻辑(如事务管理)。为了使JDK动态代理生效,目标必须至少实现一个接口;否则,Spring会自动切换至CGLIB代理[^2]。 --- #### 事务注解的作用 `@Transactional`注解用于声明事务边界,其核心功能是由Spring AOP框架通过代理机制实现的。当某个方法被标注为`@Transactional`时,Spring会为其创建一个代理对象,并在方法执行前后插入事务管理逻辑。具体而言: - 方法调用前:启动事务。 - 方法正常返回时:提交事务。 - 方法抛出异常时:根据事务传播行为和回滚规则决定是否回滚事务。 例如: ```java @Service public class OrderService implements IOrderService { @Override @Transactional public void placeOrder(Order order) { // 执行订单放置逻辑 } } ``` 在这个例子中,`placeOrder`方法会被代理对象拦截,并在其周围添加事务管理逻辑。 --- #### AOP配置对代理行为的影响 Spring AOP的核心在于切面(Aspect)的概念,它可以将横切关注点(如事务管理、日志记录等)从业务逻辑中分离出来。对于JDK动态代理来说,AOP配置决定了代理对象如何生成以及何时应用增强逻辑。 - 如果目标实现了接口,则默认使用JDK动态代理。 - 可以通过`<aop:config>`标签或`@EnableAspectJAutoProxy(proxyTargetClass = false)`显式指定优先使用JDK动态代理[^4]。 需要注意的是,JDK动态代理仅能拦截对接口方法的调用,无法拦截对非接口方法或私有方法的调用。因此,在设计服务层对象时应确保所有需要增强的方法都定义在接口中。 --- #### 服务层代理对象的行为特点 当服务层对象使用JDK动态代理时,其行为表现出如下特征: 1. **方法拦截** 代理对象会对目标的所有公共接口方法进行拦截,并在方法调用前后执行相应的增强逻辑。这使得事务管理等功能得以透明地应用于业务逻辑之中[^1]。 2. **自我调用问题** 在同一个内的方法间相互调用时,由于调用并未经过代理对象,因此不会触发事务或其他AOP增强逻辑。例如: ```java @Service public class UserService implements IUserService { @Override @Transactional public void createUser(User user) { saveUser(user); } private void saveUser(User user) { // 数据保存逻辑 } } ``` 上述代码中,`createUser`方法虽然带有`@Transactional`注解,但由于`saveUser`是同一中的私有方法,调用并不会经过代理对象,从而导致事务失效[^3]。 3. **线程安全性** 每次请求都会生成一个新的代理对象实例,这意味着代理对象本身是线程安全的。然而,目标的成员变量仍需注意线程安全问题。 --- #### 示例代码展示 以下是一个完整的示例,演示了JDK动态代理在Spring事务管理中的应用: ```java // 接口定义 public interface IUserService { void createUser(User user); } // 实现 @Service public class UserServiceImpl implements IUserService { @Override @Transactional public void createUser(User user) { System.out.println("Creating user: " + user.getName()); // 模拟数据库操作 } } // 测试 @SpringBootTest public class ServiceTest { @Autowired private IUserService userService; @Test public void testCreateUser() { User user = new User(); user.setName("John Doe"); userService.createUser(user); // 此处会触发事务管理逻辑 } } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值