Spring框架中设计模式之 代理模式(AOP模式)

代理模式:Spring AOP 使用了代理模式,将横切逻辑与业务逻辑分离,实现了对业务逻辑的解耦。

在 Spring AOP 中,代理模式被广泛使用,它通过代理对象包装目标对象,从而实现了横切逻辑的织入。具体来说,Spring AOP 通过 JDK 动态代理和 CGLIB 代理来实现代理模式,分别针对接口和类的情况进行代理。

在使用 JDK 动态代理时,Spring AOP 使用了 Proxy 类和 InvocationHandler 接口。Proxy 类是 JDK 提供的一个代理工具类,它可以动态生成代理类,同时也实现了代理对象的创建逻辑。InvocationHandler 接口定义了代理对象的方法调用逻辑,当代理对象调用方法时,实际上是由 InvocationHandler 来进行处理的。在 Spring AOP 中,当需要代理接口类型的 Bean 时,会使用 JDK 动态代理来生成代理对象。

在使用 CGLIB 代理时,Spring AOP 使用了 Enhancer 类和 MethodInterceptor 接口。Enhancer 类是 CGLIB 提供的一个代理工具类,它可以生成一个目标类的子类,并重写目标类中的方法来实现代理逻辑。MethodInterceptor 接口定义了代理对象的方法调用逻辑,当代理对象调用方法时,实际上是由 MethodInterceptor 来进行处理的。在 Spring AOP 中,当需要代理非接口类型的 Bean 时,会使用 CGLIB 代理来生成代理对象。

在 Spring AOP 中,代理对象可以实现多种增强类型,例如前置增强、后置增强、环绕增强等。这些增强类型都是通过切面来定义的,而切面本质上是一种特殊的 Bean,它包含了一组切点和增强逻辑。当 Bean 对象被代理时,代理对象会根据切面定义的切点来确定哪些方法需要增强,然后根据增强类型来执行增强逻辑。

在 Spring AOP 的源码中,ProxyFactoryBean 类是代理模式的核心类,它继承了 ProxyConfig 类,同时也实现了 FactoryBean 接口。ProxyConfig 定义了代理相关的配置信息,例如目标对象、切面、代理类型等;FactoryBean 接口定义了 Bean 的工厂类,通过实现 FactoryBean 接口,可以将普通的 Bean 转换为工厂 Bean。在 ProxyFactoryBean 中,根据代理类型的不同,会使用 JDK 动态代理或 CGLIB 代理来生成代理对象,并将代理对象注册到 Spring 的容器中。同时,ProxyFactoryBean 还支持多个切面和切点的配置,可以为 Bean 对象同时增加多个增强逻辑。

综上所述,Spring AOP 使用了代理模式,通过 JDK 动态代理和 CGLIB 代理来实现代理对象的创建,并通过切面来定义增强逻辑,从而实现横切逻辑的织入。代理对象可以实现多种增强类型,例如前置增强、后置增强、环绕增强等,而这些增强类型都是通过切面来定义的。在 Spring AOP 中,ProxyFactoryBean 类是代理模式的核心类,它继承了 ProxyConfig 类,同时也实现了 FactoryBean 接口。ProxyConfig 定义了代理相关的配置信息,例如目标对象、切面、代理类型等,而 FactoryBean 接口定义了 Bean 的工厂类,通过实现 FactoryBean 接口,可以将普通的 Bean 转换为工厂 Bean。在 ProxyFactoryBean 中,根据代理类型的不同,会使用 JDK 动态代理或 CGLIB 代理来生成代理对象,并将代理对象注册到 Spring 的容器中。同时,ProxyFactoryBean 还支持多个切面和切点的配置,可以为 Bean 对象同时增加多个增强逻辑。

下面是 Spring AOP 的代理模式的示例代码:

public interface UserService {
    void saveUser(User user);
}

public class UserServiceImpl implements UserService {
    public void saveUser(User user) {
        // 保存用户信息
    }
}

public class UserServiceAspect {
    @Before("execution(* com.example.UserService.saveUser(..))")
    public void beforeSaveUser() {
        System.out.println("before save user");
    }
}

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }

    @Bean
    public UserServiceAspect userServiceAspect() {
        return new UserServiceAspect();
    }
}

public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    UserService userService = context.getBean(UserService.class);
    userService.saveUser(new User("Alice", "123456"));
}

在上面的代码中,UserService 是一个接口类型的 Bean,它的实现类 UserServiceImpl 是需要被代理的目标对象。UserServiceAspect 是一个切面,它定义了一个前置增强,在 UserServiceImpl 的 saveUser 方法执行前打印一条日志。AppConfig 是 Spring 的配置类,通过 @EnableAspectJAutoProxy 注解启用了 Spring AOP 的自动代理功能,使得 UserServiceImpl 被代理时会自动应用 UserServiceAspect 中定义的增强逻辑。在 main 方法中,我们从容器中获取了 UserService Bean,然后调用了它的 saveUser 方法,触发了前置增强的执行,打印了一条日志。

通过上面的示例代码,我们可以看到代理模式在 Spring AOP 中的应用,即通过代理对象包装目标对象,从而实现了横切逻辑的织入,同时也展示了 Spring AOP 中代理对象的创建和切面的应用。