AOP:面向切面编程,AOP编程可不是Spring独有的,Spring只是支持AOP编程的框架之一
作用:在程序运行期间,不修改源码对已有方法增强。
优势:减少重复代码;提高开发效率;维护方便
主要功能:日志记录、性能统计、安全控制、事务处理、异常处理等。
Spring AOP默认使用JDK动态代理作为AOP代理,这使得任何接口都可以被代理,也可以使用cglib代理。
在springAop中:
前置通知:调用目标方法之前织入的内容
后置通知:调用目标方法之后织入的内容
异常通知:在catch语句块中织入的内容
最终通知:finally语句块中织入的内容
环绕通知:整个invoke方法执行的过程,称为环绕通知
joinpoint:连接点:动态代理能访问的点(方法)
pointcut:切入点:需要被增强的点(方法)
Aspect(切面):切入点(要增强的方法)与通知(如何增强)之间的关系
案例:之前学习JDBC的时候我们接触到了事务,A账户给B账户转钱,我们需要加入事务的操作,
要满足事务的一致性!!
如果用代理模式来完成对事务的织入,程序如何写?
持久层:
/*** @author shizi 2022/1/27*/@Repositorypublic class AccountDaoImpl implements AccountDao {private Connection connection = JDBCUtils.getConnection();private PreparedStatement preparedStatement = null;/**** A账户进行转账*/@Overridepublic void transfer() {try {preparedStatement = connection.prepareStatement("update test_account set banlance_A = banlance_A-? where id = ?");preparedStatement.setDouble(1,1000);preparedStatement.setInt(2,1);int i = preparedStatement.executeUpdate();System.out.println(i == 1 ?"A账户扣钱成功":"A账户扣钱失败");} catch (SQLException e) {e.printStackTrace();}}/*** 给B账户加钱*/@Overridepublic void saveAccount() {try {preparedStatement = connection.prepareStatement("update test_account set banlance_B = banlance_B+? where id = ?");preparedStatement.setDouble(1,1000);preparedStatement.setInt(2,1);int i = preparedStatement.executeUpdate();System.out.println(i == 1 ?"B账户加钱成功":"B账户加钱失败");} catch (SQLException throwables) {throwables.printStackTrace();}finally {AffairsUtils.closeAffairs();}}}
业务层:
@Service("service")public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Overridepublic void saveAccount() {accountDao.saveAccount();}@Overridepublic void transfer() {accountDao.transfer();}}
代理类:
/*** @author shizi 2022/2/3* 为业务层做代理*/@Componentpublic class AccountProxy {/*** 目标对象*/@Autowiredprivate AccountService accountService;/*** 获取代理对象* @return*/public Object getProxy(){return Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {/*** 完成对目标方法的增强:** 在springAop中:* 前置通知:调用目标方法之前织入的内容* 后置通知:调用目标方法之后织入的内容* 异常通知:在catch语句块中织入的内容* 最终通知:finally语句块中织入的内容* 环绕通知:整个invoke方法执行的过程,称为环绕通知*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object invoke = null;try {if(method.getName().equals("transfer")){AffairsUtils.beginAffairs();}//调用目标类方法invoke = method.invoke(accountService, args);if(method.getName().equals("saveAccount")){AffairsUtils.commitAffairs();}}catch (Exception e){//回滚事务AffairsUtils.rollbackAffairs();e.printStackTrace();}finally {if("saveAccount".equals(method.getName())){AffairsUtils.closeAffairs();}}return invoke;}});}}
测试类:
public class AopTest01 {private static ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);public static void main(String[] args) {//从容器中获取代理对象AccountProxy accountProxy = applicationContext.getBean("accountProxy", AccountProxy.class);AccountService proxy = (AccountService)accountProxy.getProxy();proxy.transfer();proxy.saveAccount();}}
工具类:
JDBCUtils
/*** @author shizi 2022/2/2* 为了使得数据库相关对象是单例的,所以重新封装工具类*/@Component@Configuration@PropertySource("classpath:jdbc")public class JDBCUtils {private static Connection connection;private static String username = "root";private static String password = "root";private static String driver = "com.mysql.cj.jdbc.Driver";private static String url = "jdbc:mysql://localhost:3306/test_account?serverTimezone=GMT&characterEncoding=utf-8";static {//注册驱动try {Class.forName(driver);connection= DriverManager.getConnection(url,username,password);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException throwables) {throwables.printStackTrace();}}/*** 获取实例的方法*/public static Connection getConnection(){return connection;}}
事务管理工具类:
AffairsUtils:
/*** @author shizi 2022/2/2* 事务管理工具类*/public class AffairsUtils {private AffairsUtils(){}/*** 开启事务*/public static void beginAffairs(){try {JDBCUtils.getConnection().setAutoCommit(false);} catch (SQLException throwables) {throwables.printStackTrace();}}/*** 提交事务*/public static void commitAffairs(){try {JDBCUtils.getConnection().commit();} catch (SQLException throwables) {throwables.printStackTrace();}}/*** 回滚事务*/public static void rollbackAffairs(){try {JDBCUtils.getConnection().rollback();} catch (SQLException throwables) {throwables.printStackTrace();}}/*** 关闭事务*/public static void closeAffairs(){try {JDBCUtils.getConnection().close();} catch (SQLException throwables) {throwables.printStackTrace();}}}
