组成部分
subject: 抽象主题。定义了真实主题和代理主题共同的接口
realSubject: 真实主题。实现了抽象主题接口,是代理对象所代表的真实对象。客户端直接访问真实主题,但在某些情况下,可以通过代理主题来间接访问。
proxy: 代理。实现了抽象主题接口,并持有对真实主题的引用。代理主题通常在真实主题的基础上提供一些额外的功
代理模式的实现步骤:
- 定义主题接口:创建一个接口,定义了RealSubject和Proxy共有的方法。
public interface Subject { void request(); }
- 实现真实主题:创建一个实现了主题接口的类。
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
- 创建代理类:代理类实现与真实主题相同的接口,并包含对真实主题对象的引用。
public class Proxy implements Subject {
private RealSubject realSubject;
public Proxy() {
this.realSubject = null;
}
public void setRealSubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request();
// 可以在此处添加额外的处理逻辑
}
}
- 使用代理:客户端代码通过代理类间接访问真实主题对象。
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request(); // 代理对象处理请求
}
}
能,例如延迟加载、权限控制、日志记录等。
案例:Spring框架的AOP
# JDK动态代理#
基于接口实现
package com.msq.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyExample {
/**
* 前置处理
* RealSubject: 请求方法
* 后置处理
*/
public static void main(String[] args) {
// 创建被代理对象
RealSubject realSubject = new RealSubject();
/**
* 创建代理对象
* ClassLoader loader: 代理类的类加载器。
* Class<?>[] interfaces: 一个接口数组,指定代理类需要实现的接口。代理类将实现这些接口中定义的所有方法。
* InvocationHandler h: 一个调用处理器实例,用于拦截代理实例上的方法调用,并在调用真实主题对象的方法之前或之后执行自定义逻辑。
*/
Subject proxySubject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
new Class[]{Subject.class},
new DynamicProxyHandler(realSubject));
// 使用代理对象调用方法
proxySubject.request();
}
static class DynamicProxyHandler implements InvocationHandler{
// 被代理的对象
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
/**
*
* @param proxy 代理对象的引用
* @param method 表示正在被调用的方法。
* 这个对象包含了方法的名称、返回类型、参数类型等信息,你可以通过这个Method对象来判断正在调用的具体是哪个方法
* @param args 包含被调用方法的参数。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置处理");
Object result = method.invoke(target, args);
if (method.getName().equals("write")){
System.out.println(method.getDefaultValue());
}
System.out.println("后置处理");
return result;
}
}
}
# CGlib动态代理#
类代理
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.InvocationHandler; // CGLIB 3.0 以后使用 InvocationHandler
// 定义一个目标类,不需要实现任何接口
class RealObject {
public void performAction() {
System.out.println("Real object performing action.");
}
}
// 定义一个拦截器,实现 MethodInterceptor 接口。代理类
class MyMethodInterceptor implements MethodInterceptor {
// 重写 intercept 方法,用于拦截目标方法的调用
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("前置处理.");
// 调用目标方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置处理.");
return result;
}
// 实现一个方法来处理方法调用的异常
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
try {
return intercept(obj, method, args, proxy);
} catch (Exception e) {
// 异常处理逻辑
throw e;
}
}
}
// client类
public class CglibProxyDemo {
public static void main(String[] args) {
// 创建 Enhancer 对象,它是 CGLIB 的核心类,用于增强类
Enhancer enhancer = new Enhancer();
// 设置 Enhancer 的父类,即目标类
enhancer.setSuperclass(RealObject.class);
// 设置回调,即拦截器
enhancer.setCallback(new MyMethodInterceptor());
// 创建代理对象,它扩展了目标类
RealObject proxyInstance = (RealObject) enhancer.create();
// 调用代理对象的方法,实际调用的是拦截器的 intercept 方法
proxyInstance.performAction();
}
}
pom依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version></version>
</dependency>
# 扩展一:Spring Aop#
aop概念点
- JoinPoint(连接点):表示程序执行过程中可以插入额外逻辑的点,通常是方法的调用。
- Pointcut(切入点):是对JoinPoint的表达式选择,用于确定哪些JoinPoint需要被拦截。
- Advice(通知):在特定的JoinPoint上执行的代码,可以是方法的前置、后置、异常处理或环绕通知。
- Aspect(切面):一个或多个Advice的集合,以及它们应用的Pointcut。
- Proxy(代理):Spring AOP会为目标对象创建代理,代理会拦截方法调用并应用Advice。
- Target(目标对象):被代理的对象。
- Weaving(织入):将Aspect应用到Target的过程。
代理的类型
-
JDK动态代理:如果目标对象实现了至少一个接口,Spring AOP会使用JDK的
Proxy
类来创建代理对象。 -
CGLIB代理:如果目标对象没有实现接口,Spring AOP会使用CGLIB库来为目标对象创建一个子类,并在子类中实现代理。
Spring AOP还支持其他类型的代理,如使用AspectJ
的AOP实现,但这通常需要引入额外的依赖和配置。
Spring AOP的步骤:
- 定义切面,包括切入点和通知。
- 配置切面,指定目标对象和代理类型。
- 织入切面,将切面应用到目标对象。
@Component
@Aspect
// 定义一个切面
public class MyAspect {
/*
@Before("execution(* com.example.service.*.*(..)) && this(target)")
public void beforeAdvice(JoinPoint joinPoint, Object target) {
// 直接通过目标对象引用修改属性
((YourClass) target).yourProperty = newValue;
}
*/
// 连接点、切入点、通知
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
// 执行前置通知
// 获取目标对象
Object target = joinPoint.getTarget();
Field field = target.getClass().getDeclaredField("yourProperty");
field.setAccessible(true);
field.set(target, newValue);
}
// 连接点、切入点、通知
@After("execution(* com.example.service.*.*(..))")
public void afterAdvice() {
// 执行后置通知
}
// 可以添加其他类型的Advice
}
spring声明式事务 @Transactional
在Spring Boot架构中,通过自动配置(auto-configuration)和条件注解(
@Conditional
)进一步简化了配置过程。以下是Spring Boot中声明式事务管理的关键步骤:
添加依赖: 确保你的Spring Boot项目中包含了Spring Boot的事务依赖,通常是
spring-boot-starter-data-jpa
或spring-boot-starter-jdbc
,这取决于你使用的是JPA还是JDBC。配置数据源: 在
application.properties
或application.yml
中配置数据库连接信息,Spring Boot会自动配置数据源。启用事务管理: Spring Boot自动配置机制会检测到
@EnableTransactionManagement
的存在,并自动启用基于注解的事务管理。你不需要显式地在配置类上添加这个注解,因为Spring Boot的自动配置已经包含了它。使用
@Transactional
注解: 在服务层或数据访问层的类或方法上使用@Transactional
注解来声明事务边界。Spring Boot会自动扫描这些注解,并使用AOP来创建代理,管理事务。自动代理创建: Spring Boot使用
@EnableAutoConfiguration
或@SpringBootApplication
注解来激活自动配置。这包括了TransactionInterceptor
用于拦截被@Transactional
注解的方法;AnnotationAwareAspectJAutoProxyCreator
,它会自动为使用@Transactional
注解的Bean创建代理。这个自动代理创建器会扫描所有的beans,如果发现有@Transactional
注解的beans,就会为它们创建代理。事务属性的配置:
@Transactional
注解本身包含了多个属性,如propagation
(传播行为)、isolation
(隔离级别)、timeout
(超时时间)、readOnly
(只读标志)等,这些属性定义了事务的具体行为。如果方法抛出异常,并且根据rollbackFor
属性或其他规则需要回滚,事务将被回滚。事务管理器的配置: 如果你使用的是JPA,Spring Boot会默认配置一个
JpaTransactionManager
。对于JDBC,会配置一个DataSourceTransactionManager
。你可以通过配置文件或Java配置来自定义事务管理器。自定义事务配置: 也可以自定义事务配置,例如通过实现TransactionManagementConfigurer
接口来提供自定义的PlatformTransactionManager
。事务同步管理器: 使用
TransactionSynchronizationManager
来注册事务同步处理器,这些处理器可以在事务的不同阶段(如提交前后或回滚前后)执行额外的任务。Spring Boot的监控和管理: Spring Boot提供了多种监控和管理功能,例如健康检查、度量信息收集等,这些可以帮助你监控事务的状态和性能。