AOP:面向切面编程,AOP编程可不是Spring独有的,Spring只是支持AOP编程的框架之一
    作用:在程序运行期间,不修改源码对已有方法增强。
    优势:减少重复代码;提高开发效率;维护方便
    主要功能:日志记录、性能统计、安全控制、事务处理、异常处理等。
    Spring AOP默认使用JDK动态代理作为AOP代理,这使得任何接口都可以被代理,也可以使用cglib代理。

    在springAop中:

    前置通知:调用目标方法之前织入的内容

    后置通知:调用目标方法之后织入的内容

    异常通知:在catch语句块中织入的内容

    最终通知:finally语句块中织入的内容

    环绕通知:整个invoke方法执行的过程,称为环绕通知
    joinpoint:连接点:动态代理能访问的点(方法)
    pointcut:切入点:需要被增强的点(方法)
    Aspect(切面):切入点(要增强的方法)与通知(如何增强)之间的关系

    案例:之前学习JDBC的时候我们接触到了事务,A账户给B账户转钱,我们需要加入事务的操作,
    要满足事务的一致性!!

    如果用代理模式来完成对事务的织入,程序如何写?
    持久层:

    1. /**
    2. * @author shizi 2022/1/27
    3. */
    4. @Repository
    5. public class AccountDaoImpl implements AccountDao {
    6. private Connection connection = JDBCUtils.getConnection();
    7. private PreparedStatement preparedStatement = null;
    8. /**
    9. *
    10. * A账户进行转账
    11. */
    12. @Override
    13. public void transfer() {
    14. try {
    15. preparedStatement = connection.prepareStatement("update test_account set banlance_A = banlance_A-? where id = ?");
    16. preparedStatement.setDouble(1,1000);
    17. preparedStatement.setInt(2,1);
    18. int i = preparedStatement.executeUpdate();
    19. System.out.println(i == 1 ?"A账户扣钱成功":"A账户扣钱失败");
    20. } catch (SQLException e) {
    21. e.printStackTrace();
    22. }
    23. }
    24. /**
    25. * 给B账户加钱
    26. */
    27. @Override
    28. public void saveAccount() {
    29. try {
    30. preparedStatement = connection.prepareStatement("update test_account set banlance_B = banlance_B+? where id = ?");
    31. preparedStatement.setDouble(1,1000);
    32. preparedStatement.setInt(2,1);
    33. int i = preparedStatement.executeUpdate();
    34. System.out.println(i == 1 ?"B账户加钱成功":"B账户加钱失败");
    35. } catch (SQLException throwables) {
    36. throwables.printStackTrace();
    37. }finally {
    38. AffairsUtils.closeAffairs();
    39. }
    40. }
    41. }

    业务层:

    1. @Service("service")
    2. public class AccountServiceImpl implements AccountService {
    3. @Autowired
    4. private AccountDao accountDao;
    5. @Override
    6. public void saveAccount() {
    7. accountDao.saveAccount();
    8. }
    9. @Override
    10. public void transfer() {
    11. accountDao.transfer();
    12. }
    13. }

    代理类:

    1. /**
    2. * @author shizi 2022/2/3
    3. * 为业务层做代理
    4. */
    5. @Component
    6. public class AccountProxy {
    7. /**
    8. * 目标对象
    9. */
    10. @Autowired
    11. private AccountService accountService;
    12. /**
    13. * 获取代理对象
    14. * @return
    15. */
    16. public Object getProxy(){
    17. return Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {
    18. /**
    19. * 完成对目标方法的增强:
    20. *
    21. * 在springAop中:
    22. * 前置通知:调用目标方法之前织入的内容
    23. * 后置通知:调用目标方法之后织入的内容
    24. * 异常通知:在catch语句块中织入的内容
    25. * 最终通知:finally语句块中织入的内容
    26. * 环绕通知:整个invoke方法执行的过程,称为环绕通知
    27. */
    28. @Override
    29. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    30. Object invoke = null;
    31. try {
    32. if(method.getName().equals("transfer")){
    33. AffairsUtils.beginAffairs();
    34. }
    35. //调用目标类方法
    36. invoke = method.invoke(accountService, args);
    37. if(method.getName().equals("saveAccount")){
    38. AffairsUtils.commitAffairs();
    39. }
    40. }catch (Exception e){
    41. //回滚事务
    42. AffairsUtils.rollbackAffairs();
    43. e.printStackTrace();
    44. }finally {
    45. if("saveAccount".equals(method.getName())){
    46. AffairsUtils.closeAffairs();
    47. }
    48. }
    49. return invoke;
    50. }
    51. });
    52. }
    53. }

    测试类:

    1. public class AopTest01 {
    2. private static ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
    3. public static void main(String[] args) {
    4. //从容器中获取代理对象
    5. AccountProxy accountProxy = applicationContext.getBean("accountProxy", AccountProxy.class);
    6. AccountService proxy = (AccountService)accountProxy.getProxy();
    7. proxy.transfer();
    8. proxy.saveAccount();
    9. }
    10. }

    工具类:
    JDBCUtils

    1. /**
    2. * @author shizi 2022/2/2
    3. * 为了使得数据库相关对象是单例的,所以重新封装工具类
    4. */
    5. @Component
    6. @Configuration
    7. @PropertySource("classpath:jdbc")
    8. public class JDBCUtils {
    9. private static Connection connection;
    10. private static String username = "root";
    11. private static String password = "root";
    12. private static String driver = "com.mysql.cj.jdbc.Driver";
    13. private static String url = "jdbc:mysql://localhost:3306/test_account?serverTimezone=GMT&characterEncoding=utf-8";
    14. static {
    15. //注册驱动
    16. try {
    17. Class.forName(driver);
    18. connection= DriverManager.getConnection(url,username,password);
    19. } catch (ClassNotFoundException e) {
    20. e.printStackTrace();
    21. } catch (SQLException throwables) {
    22. throwables.printStackTrace();
    23. }
    24. }
    25. /**
    26. * 获取实例的方法
    27. */
    28. public static Connection getConnection(){
    29. return connection;
    30. }
    31. }

    事务管理工具类:
    AffairsUtils:

    1. /**
    2. * @author shizi 2022/2/2
    3. * 事务管理工具类
    4. */
    5. public class AffairsUtils {
    6. private AffairsUtils(){}
    7. /**
    8. * 开启事务
    9. */
    10. public static void beginAffairs(){
    11. try {
    12. JDBCUtils.getConnection().setAutoCommit(false);
    13. } catch (SQLException throwables) {
    14. throwables.printStackTrace();
    15. }
    16. }
    17. /**
    18. * 提交事务
    19. */
    20. public static void commitAffairs(){
    21. try {
    22. JDBCUtils.getConnection().commit();
    23. } catch (SQLException throwables) {
    24. throwables.printStackTrace();
    25. }
    26. }
    27. /**
    28. * 回滚事务
    29. */
    30. public static void rollbackAffairs(){
    31. try {
    32. JDBCUtils.getConnection().rollback();
    33. } catch (SQLException throwables) {
    34. throwables.printStackTrace();
    35. }
    36. }
    37. /**
    38. * 关闭事务
    39. */
    40. public static void closeAffairs(){
    41. try {
    42. JDBCUtils.getConnection().close();
    43. } catch (SQLException throwables) {
    44. throwables.printStackTrace();
    45. }
    46. }
    47. }