目录
- 1. 代理
- 1.1 **JDK 动态代理**
- 1.2 **CGLIB 代理**
- 1.3 JDK 动态代理与 CGLIB 的对比
 
- 2. AOP思想
- 2.1 基本概念
- 2.2 AspectJ 技术
- 2.3 **AspectJ 使用 XML 配置**
- 2.4 **AspectJ 使用注解配置**
- 2.5 通知
 
- 3. JdbcTemplate
- 3.1 **主要特点**
- 3.2 **核心方法**
- 3.3 **使用步骤**
- 3.4 **优点**
 
- 4. 配置平台事务管理器和事务管理模板
- 4.1 配置平台事务管理器
- 4.2 配置事务管理模板
- 4.2.1 编程式事务管理
- 4.2.2 声明式事务管理
 
 
1. 代理
1.1 JDK 动态代理
JDK 动态代理是 Java 标准库自带的一种代理机制,基于 接口 实现。它的核心是 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。
特点
- 基于接口:JDK 动态代理只能代理实现了接口的目标对象。
- 性能较低:相较于 CGLIB,JDK 动态代理在运行时的性能稍低。
- 灵活性高:可以在运行时动态生成代理类,适用于需要动态增强接口方法的场景。
实现步骤
- 定义接口:目标对象需要实现一个接口。
- 实现 InvocationHandler:用于处理代理类的方法调用。
- 生成代理对象:通过 Proxy.newProxyInstance()方法生成代理对象。
示例代码
- 定义接口
public interface BankService {
    void transferMoney(Long fromAccountId, Long toAccountId, double amount);
}
- 实现目标类
public class BankServiceImpl implements BankService {
    @Override
    public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
        System.out.println("Transferring money from account " + fromAccountId + " to account " + toAccountId);
    }
}
- 实现 InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TransactionHandler implements InvocationHandler {
    private Object target; // 目标对象
    public TransactionHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 事务控制逻辑
        System.out.println("Transaction started...");
        try {
            Object result = method.invoke(target, args); // 调用目标方法
            System.out.println("Transaction committed.");
            return result;
        } catch (Exception e) {
            System.out.println("Transaction rolled back.");
            throw e;
        }
    }
}
- 生成代理对象
import java.lang.reflect.Proxy;
public class Main {
    public static void main(String[] args) {
        // 目标对象
        BankService target = new BankServiceImpl();
        // 创建 InvocationHandler
        TransactionHandler handler = new TransactionHandler(target);
        // 生成代理对象
        BankService proxy = (BankService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(), // 类加载器
            target.getClass().getInterfaces(), // 目标类实现的接口
            handler // InvocationHandler
        );
        // 调用代理对象的方法
        proxy.transferMoney(1L, 2L, 100.0);
    }
}
输出结果
Transaction started...
Transferring money from account 1 to account 2
Transaction committed.
1.2 CGLIB 代理
CGLIB(Code Generation Library)是一种基于 字节码生成 的代理技术,允许代理 没有实现接口的类。它的核心是 net.sf.cglib.proxy.Enhancer 类和 net.sf.cglib.proxy.MethodInterceptor 接口。
特点
- 基于类:CGLIB 可以代理没有实现接口的类。
- 性能较高:CGLIB 生成的代理类直接基于目标类的字节码,性能通常优于 JDK 动态代理。
- 动态生成子类:CGLIB 通过生成目标类的子类来实现代理。
 实现步骤
- 定义目标类:目标类不需要实现接口。
- 实现 MethodInterceptor:用于处理代理类的方法调用。
- 生成代理对象:通过 Enhancer类生成代理对象。
示例代码
- 定义目标类
public class BankService {
    public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
        System.out.println("Transferring money from account " + fromAccountId + " to account " + toAccountId);
    }
}
- 实现 MethodInterceptor
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class TransactionInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 事务控制逻辑
        System.out.println("Transaction started...");
        try {
            Object result = proxy.invokeSuper(obj, args); // 调用目标方法
            System.out.println("Transaction committed.");
            return result;
        } catch (Exception e) {
            System.out.println("Transaction rolled back.");
            throw e;
        }
    }
}
- 生成代理对象
import net.sf.cglib.proxy.Enhancer;
public class Main {
    public static void main(String[] args) {
        // 创建 Enhancer 对象
        Enhancer enhancer = new Enhancer();
        // 设置目标类的父类
        enhancer.setSuperclass(BankService.class);
        // 设置 MethodInterceptor
        enhancer.setCallback(new TransactionInterceptor());
        // 生成代理对象
        BankService proxy = (BankService) enhancer.create();
        // 调用代理对象的方法
        proxy.transferMoney(1L, 2L, 100.0);
    }
}
输出结果
Transaction started...
Transferring money from account 1 to account 2
Transaction committed.
1.3 JDK 动态代理与 CGLIB 的对比
| 特性 | JDK 动态代理 | CGLIB 代理 | 
|---|---|---|
| 基于 | 接口 | 类 | 
| 性能 | 较低(基于反射) | 较高(基于字节码生成) | 
| 目标对象 | 必须实现接口 | 可以是任意类 | 
| 代理对象 | 代理接口 | 生成目标类的子类 | 
| 适用场景 | 需要代理接口方法 | 需要代理没有接口的类 | 
| 依赖 | JDK 自带 | 需要额外依赖 CGLIB 库 | 
2. AOP思想
2.1 基本概念
AOP(Aspect-Oriented Programming) 是一种编程范式,旨在通过将横切关注点(Cross-Cutting Concerns)从核心业务逻辑中分离出来,提高代码的模块化程度。横切关注点是指那些在多个模块中都会用到的功能,例如日志记录、事务管理、安全性检查等。AOP 的核心思想是将这些横切关注点从核心业务逻辑中解耦,封装成独立的模块(切面),并通过配置或注解的方式,将它们动态地应用到需要增强的类或方法上。
AOP 的关键术语
- 切面(Aspect):模块化的横切关注点,例如日志记录、事务管理等。
- 连接点(Join Point):程序执行过程中的某个点,例如方法调用、异常抛出等。
- 通知(Advice):切面在特定的连接点上执行的动作,例如在方法调用前后执行的日志记录。
- 切点(Pointcut):定义了通知应该应用到哪些连接点的规则,例如所有以 transferMoney开头的方法。
- 引入(Introduction):允许向现有的类添加新方法或属性。
- 织入(Weaving):将切面应用到目标对象的过程,可以在编译时、类加载时或运行时进行。
2.2 AspectJ 技术
AspectJ 是一个成熟的 AOP 框架,提供了丰富的语法和工具,支持在 Java 应用中实现 AOP。AspectJ 可以在编译时或运行时将切面织入到目标类中。
AspectJ 的主要特点
- 强大的定义切点的能力:AspectJ 提供了灵活的切点表达式,可以精确地指定通知应该应用到哪些方法或代码块。
- 多种通知类型:支持多种通知类型,包括前置通知(Before)、后置通知(After)、环绕通知(Around)等。
- 编译时织入:可以在编译时将切面织入到目标类中,提高运行时性能。
- 运行时织入:也可以在运行时通过代理或字节码操作将切面织入到目标类中。
- 丰富的注解和 XML 配置:支持通过注解或 XML 配置来定义切面和切点。
2.3 AspectJ 使用 XML 配置
添加 AspectJ 依赖
 如果使用 Maven,在 pom.xml 中添加 AspectJ 的依赖。
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.7</version>
</dependency>
实例代码
1. 切面类
public class LoggingAspect {
    // 前置通知
    public void logBefore() {
        System.out.println("Logging before method execution");
    }
}
2. 目标类
package com.example.service;
public class BankService {
    public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
        System.out.println("Transferring money from account " + fromAccountId + " to account " + toAccountId);
    }
}
3. XML 配置文件
在 XML 配置文件中定义切面、切点和通知:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 定义目标 bean -->
    <bean id="bankService" class="com.example.service.BankService" />
    <!-- 定义切面 bean -->
    <bean id="loggingAspect" class="com.example.aspect.LoggingAspect" />
    <!-- 定义切面 -->
    <aop:config>
        <!-- 定义切点 -->
        <aop:pointcut id="serviceMethods" expression="execution(* com.example.service.*.*(..))"/>
        <!-- 定义切面和通知 -->
        <aop:aspect ref="loggingAspect">
            <aop:before pointcut-ref="serviceMethods" method="logBefore"/>
        </aop:aspect>
    </aop:config>
</beans>
4. 测试代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BankService bankService = context.getBean(BankService.class);
        bankService.transferMoney(1L, 2L, 100.0);
    }
}
输出结果
Logging before method execution
Transferring money from account 1 to account 2
2.4 AspectJ 使用注解配置
添加 AspectJ 依赖
 如果使用 Maven,在 pom.xml 中添加 AspectJ 的依赖。
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.7</version>
</dependency>
实例代码
1. 切面类
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect  // 标记这是一个切面
public class LoggingAspect {
    // 定义切点
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceMethods() {}
    // 定义前置通知
    @Before("serviceMethods()")
    public void logBefore() {
        System.out.println("Logging before method execution");
    }
}
2. 目标类
package com.example.service;
public class BankService {
    public void transferMoney(Long fromAccountId, Long toAccountId, double amount) {
        System.out.println("Transferring money from account " + fromAccountId + " to account " + toAccountId);
    }
}
3. Spring 配置文件
如果使用 Spring,需要在 Spring 的 XML 配置文件中启用注解支持:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 启用 AspectJ 注解支持 -->
    <aop:aspectj-autoproxy/>
    <!-- 定义切面 bean -->
    <bean id="loggingAspect" class="com.example.aspect.LoggingAspect" />
    <!-- 定义目标 bean -->
    <bean id="bankService" class="com.example.service.BankService" />
</beans>
4. 测试代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BankService bankService = context.getBean(BankService.class);
        bankService.transferMoney(1L, 2L, 100.0);
    }
}
输出结果
Logging before method execution
Transferring money from account 1 to account 2
2.5 通知
AspectJ 提供了多种通知(Advice)类型,每种通知类型在不同的连接点(Join Point)上执行不同的逻辑。以下是 AspectJ 中常见的通知类型及其作用和语法。
1. Before 通知(前置通知)
- 作用:在目标方法执行之前执行。
- 语法:
@Aspect
public class BeforeAspect {
    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}
    @Before("serviceMethods()")  // 前置通知
    public void beforeAdvice() {
        System.out.println("Before advice executed");
    }
}
2. After 通知(后置通知)
- 作用:在目标方法执行之后执行(无论方法是否抛出异常)。
- 语法:
@Aspect
public class AfterAspect {
    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}
    @After("serviceMethods()")  // 后置通知
    public void afterAdvice() {
        System.out.println("After advice executed");
    }
}
3. AfterReturning 通知(返回通知)
- 作用:在目标方法成功返回且没有抛出异常时执行。
- 语法:
@Aspect
public class AfterReturningAspect {
    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}
    @AfterReturning(pointcut = "serviceMethods()", returning = "result")  // 返回通知
    public void afterReturningAdvice(Object result) {
        System.out.println("AfterReturning advice executed. Result: " + result);
    }
}
- 参数说明: 
  - returning = "result":将方法返回值绑定到通知方法的参数- result。
 
4. AfterThrowing 通知(异常通知)
- 作用:在目标方法抛出异常时执行。
- 语法:
@Aspect
public class AfterThrowingAspect {
    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}
    @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")  // 异常通知
    public void afterThrowingAdvice(Exception ex) {
        System.out.println("AfterThrowing advice executed. Exception: " + ex.getMessage());
    }
}
- 参数说明: 
  - throwing = "ex":将异常对象绑定到通知方法的参数- ex。
 
5. Around 通知(环绕通知)
- 作用:在目标方法执行前后执行,并且可以完全控制方法的执行流程。
- 语法:
@Aspect
public class AroundAspect {
    @Pointcut("execution(* com.example.service.*.*(..))")  // 定义切点
    public void serviceMethods() {}
    @Around("serviceMethods()")  // 环绕通知
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around advice: Before method execution");
        // 调用目标方法
        Object result = joinPoint.proceed();
        System.out.println("Around advice: After method execution");
        return result;
    }
}
- 关键点: 
  - ProceedingJoinPoint是关键对象,调用其- proceed()方法以执行目标方法。
- 可以修改方法的返回值,或完全阻止方法的执行。
 
3. JdbcTemplate
JdbcTemplate 是 Spring 框架提供的一个核心工具类,用于简化 JDBC 操作。它封装了 JDBC 的繁琐操作(如连接管理、异常处理、资源释放等),使开发者能够更专注于 SQL 语句和业务逻辑的实现。
引入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
</dependencies>
3.1 主要特点
-  简化 JDBC 操作: - 自动管理数据库连接、语句和结果集的创建与释放。
- 减少样板代码,提高开发效率。
 
-  统一的异常处理: - 将 JDBC 的 SQLException转换为 Spring 的DataAccessException,提供更清晰的异常层次结构。
 
- 将 JDBC 的 
-  支持多种操作: - 支持查询、更新、批量操作、存储过程调用等。
 
-  与 Spring 集成: - 与 Spring 的事务管理、数据源等无缝集成。
 
3.2 核心方法
1. 更新操作(增删改)
-  update():用于执行 INSERT、UPDATE、DELETE 等 SQL 语句。int update(String sql, Object... args);示例: String sql = "UPDATE users SET name = ? WHERE id = ?"; int rows = jdbcTemplate.update(sql, "John", 1);
2. 查询操作
-  queryForObject():查询单行数据并映射为对象。<T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args);示例: String sql = "SELECT * FROM users WHERE id = ?"; User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), 1);
-  query():查询多行数据并映射为对象列表。<T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args);示例: String sql = "SELECT * FROM users"; List<User> users = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));
3. 执行任意 SQL
-  execute():用于执行任意 SQL 语句(如 DDL 语句)。void execute(String sql);示例: jdbcTemplate.execute("CREATE TABLE users (id INT, name VARCHAR(100))");
3.3 使用步骤
-  配置数据源: -  在 Spring 配置文件中配置数据源(如 DataSource)。
-  示例: <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean>
 
-  
-  创建 JdbcTemplate: -  将数据源注入到 JdbcTemplate中。
-  示例: <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean>
 
-  
-  在代码中使用: -  通过依赖注入获取 JdbcTemplate实例并调用其方法。
-  示例: @Autowired private JdbcTemplate jdbcTemplate; public void addUser(User user) { String sql = "INSERT INTO users (name, age) VALUES (?, ?)"; jdbcTemplate.update(sql, user.getName(), user.getAge()); }
 
-  
3.4 优点
- 简化代码: 
  - 减少 JDBC 样板代码,提高开发效率。
 
- 异常处理: 
  - 提供统一的异常处理机制,避免繁琐的 try-catch块。
 
- 提供统一的异常处理机制,避免繁琐的 
- 与 Spring 集成: 
  - 与 Spring 的事务管理、数据源等无缝集成。
 
- 灵活性: 
  - 支持自定义 RowMapper和ResultSetExtractor,满足复杂需求。
 
- 支持自定义 
4. 配置平台事务管理器和事务管理模板
在 Spring 框架中,事务管理是一个非常重要的功能,用于确保数据库操作的完整性。Spring 提供了多种事务管理方式,其中最常见的两种是声明式事务管理和编程式事务管理。
4.1 配置平台事务管理器
平台事务管理器是 Spring 事务管理的核心接口,它负责事务的开始、提交和回滚。最常见的实现是 DataSourceTransactionManager,用于管理 JDBC 数据源的事务。
- 配置数据源
首先,需要配置一个数据源。这里我们使用 DriverManagerDataSource 作为示例数据源:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/test"/>
    <property name="username" value="root"/>
    <property name="password" value="password"/>
</bean>
- 配置平台事务管理器
接下来,配置 DataSourceTransactionManager,将数据源注入到事务管理器中:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
4.2 配置事务管理模板
事务管理模板(TransactionTemplate)是一个辅助类,用于简化事务管理的编程式操作。它可以自动管理事务的开始、提交和回滚。
配置事务管理模板
在 Spring 配置文件中配置 TransactionTemplate,并将平台事务管理器注入到模板中:
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager"/>
</bean>
4.2.1 编程式事务管理
使用 TransactionTemplate 进行编程式事务管理,可以通过 lambda 表达式或 TransactionCallback 接口来实现。
示例代码
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private JdbcTemplate jdbcTemplate;
public void addUser(User user) {
    transactionTemplate.execute(status -> {
        try {
            String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
            jdbcTemplate.update(sql, user.getName(), user.getAge());
            // 模拟异常
            // int i = 1 / 0;
            return null;
        } catch (Exception e) {
            // 回滚事务
            status.setRollbackOnly();
            throw e;
        }
    });
}
4.2.2 声明式事务管理
声明式事务管理通过在 Spring 配置文件中使用 AOP 配置事务,实现更简洁的事务管理。
- 配置事务管理器
确保已经配置了 DataSourceTransactionManager。
- 配置事务管理器的 AOP 支持
使用 tx:annotation-driven 开启基于注解的事务管理:
<tx:annotation-driven transaction-manager="transactionManager"/>
- 使用 @Transactional注解
在需要事务管理的类或方法上使用 @Transactional 注解:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Transactional
    public void addUser(User user) {
        String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
        jdbcTemplate.update(sql, user.getName(), user.getAge());
        // 模拟异常
        // int i = 1 / 0;
    }
}



















