文章目录

  • 第一章:AOP概念的引入
    • 第一种方式:
    • 第二种方式:
  • 第二章:AOP相关的概念
    • 1. AOP的概述
    • 2. AOP的优势
  • 第三章:Spring的AOP技术-配置文件方式
    • 1. AOP相关的术语
    • 2.AOP配置文件方式的入门
    • 3. 切入点的表达式
    • 4. AOP的通知类型
  • 第四章:Spring的AOP技术-注解方式
    • 1. AOP注解方式入门程序
    • 2. 通知类型的注解
    • 3. 纯注解的方式

第一章:AOP概念的引入

  1. 编写入门案例,完成AOP概念的引入
    创建maven的项目,引入开发的坐标
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- 连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!-- mysql驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency>
</dependencies>

TxUtils事务管理工具类编写

public class TxUtils {private static DruidDataSource ds = null;/*** 创建线程局部变量 存放数据库连接对象*/private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();/*** 静态代码块中创建数据库连接池*/static {try {ds =  new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql://localhost:3308/spring_db");ds.setUsername("root");ds.setPassword("root");} catch (Exception e) {throw new ExceptionInInitializerError();}}private static DruidDataSource getDataSource(){return ds;}/*** 获取数据库连接**/public static  Connection getConnection() throws SQLException {Connection conn = threadLocal.get();if (conn == null) {conn = getDataSource().getConnection();threadLocal.set(conn);}return conn;}/*** 开启事务*/public static void start() {try {Connection conn = threadLocal.get();if (conn == null) {conn = ds.getConnection();threadLocal.set(conn);}conn.setAutoCommit(false);} catch (Exception e) {throw  new RuntimeException(e);}}/*** 提交事务*/public static void commit() {try {Connection conn = threadLocal.get();if (conn != null) {conn.commit();}} catch (Exception e) {throw  new RuntimeException(e);}}/*** 回滚事务*/public static void rollback() {try {Connection conn = threadLocal.get();if (conn != null) {conn.rollback();}} catch (Exception e) {throw  new RuntimeException(e);}}/*** 释放资源,关闭连接*/public static void close() {try {Connection conn = threadLocal.get();if(conn != null){// 关闭数据库连接conn.close();// 局部线程解绑threadLocal.remove();}} catch (Exception e) {throw  new RuntimeException(e);}}}

第一种方式:

AccountServiceImpl业务层(自己编写除业务之外的代码:保证多个操作是一个事务)代码如下

public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}public void saveAll(Account account1,Account account2) {try {//System.out.println("业务层保存账户");TxUtils.start();//保存1账户accountDao.save(account1);//模拟异常//int a = 1/0;//保存1账户accountDao.save(account2);TxUtils.commit();} catch (SQLException e) {e.printStackTrace();TxUtils.rollback();} finally {TxUtils.close();}}}

AccountDaoImpl 持久层代码如下:
要点:
1、获取连接不从druid连接池中获取,而是从TxUtils这个事务管理工具类的线程中获取,保证多个操作是在一个线程下。
2、一个数据库操作完成后,不要关闭数据库连接资源,否则每个操作就是多个线程了,不在一线程下了


public class AccountDaoImpl implements AccountDao {public void save(Account account) throws SQLException {// System.out.println("持久层:保存账户");Connection conn = TxUtils.getConnection();String sql ="insert into account values (null,?,?)";PreparedStatement stmt = conn.prepareStatement(sql);stmt.setString(1,account.getName());stmt.setDouble(2,account.getMoney());stmt.executeUpdate();stmt.close();}
}

测试的方法如下


public class Demo1 {@Testpublic void run1() throws SQLException {ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");AccountService accountService = (AccountService) ac.getBean("accountService");Account account1 = new Account();account1.setName("熊哥");account1.setMoney(3000d);Account account2 = new Account();account2.setName("美美");account2.setMoney(2000d);//调用对象方法accountService.saveAll(account1,account2);}
}

测试方案:在Accountservice实现类中模拟异常,执行测试方法,观察数据库操作是否回滚

第二种方式:

采用jdk的动态代理技术编写工具类,目的是为了简化service层,工具类具体代码如下:


public class JdkProxy {/*** 使用Jdk的动态代理生成代理对象* newProxyInstance()三个参数,* 第一个是类加载器,要获得代理对象,是在类运行时获取的,所有需要提供类加载器* 第二个参数是代理对象要实现的接口,代理对象是代替接口的实现类的对象工作,所以不仅要完成增强的工作,还要实现接口* 第三个参数是回调函数*/public static Object getProxy(AccountService accountService) {Object proxy = Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try {TxUtils.start();result = method.invoke(accountService, args);TxUtils.commit();} catch (Exception e) {e.printStackTrace();TxUtils.rollback();} finally {TxUtils.close();}return result;}});//返回增强后的代理对象return proxy;}
}

AccountServiceImpl业务层(不用自己编写除业务之外的代码)代码如下:

public class AccountServiceImpl implements AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}/*保存两个账号*/public void SaveAll(Account account1, Account account2) {accountDao.save(account1);//模拟异常//int a = 1/0;accountDao.save(account2);}}

AccountDaoImpl 持久层代码不需要修改依然如下:


public class AccountDaoImpl implements AccountDao {public void save(Account account) throws SQLException {// System.out.println("持久层:保存账户");Connection conn = TxUtils.getConnection();String sql ="insert into account values (null,?,?)";PreparedStatement stmt = conn.prepareStatement(sql);stmt.setString(1,account.getName());stmt.setDouble(2,account.getMoney());stmt.executeUpdate();stmt.close();}
}

获取代理对象调用增强后的方法,测试的代码如下

public class Demo1 {@Testpublic void run1() throws SQLException {ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");AccountService accountService = (AccountService) ac.getBean("accountService");Account account1 = new Account();account1.setName("熊哥");account1.setMoney(3000d);Account account2 = new Account();account2.setName("美美");account2.setMoney(2000d);//生成代理对象Object proxyobj = JdkProxy.getProxy(accountService);//强转AccountService proxy = (AccountService) proxyobj;//调用代理对象方法proxy.saveAll(account1,account2);}
}

测试方案:在Accountservice实现类中模拟异常,执行测试方法,观察数据库操作是否回滚

第二章:AOP相关的概念

1. AOP的概述

什么是AOP的技术?
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程

  • AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
  • AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范
  • 通过预编译方式或者运行期动态代理实现程序功能的统一维护的一种技术
    AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型
  • 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
  • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(事务管理、安全检查、缓存)

为什么要学习AOP,可以在不修改源代码的前提下,对程序进行增强!!

2. AOP的优势

运行期间,不修改源代码的情况下对已有的方法进行增强
优势:

  1. 减少重复的代码
  2. 提供开发的效率
  3. 维护方便
  4. AOP的底层原理
    JDK的动态代理技术
    1、为接口创建代理类的字节码文件
    2、使用ClassLoader将字节码文件加载到JVM
    3、创建代理类实例对象,执行对象的目标方法
    cglib代理技术
    为类生成代理对象,被代理类有没有接口都无所谓,底层是生成子类,继承被代理类

第三章:Spring的AOP技术-配置文件方式

1. AOP相关的术语

  • Joinpoint(连接点) 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
  • Pointcut(切入点) – 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
  • Advice(通知/增强)–
    所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
  • Target(目标对象)-- 代理的目标对象
  • Weaving(织入)-- 是指把增强应用到目标对象来创建新的代理对象的过程
  • Proxy(代理)-- 一个类被AOP织入增强后,就产生一个结果代理类
  • Aspect(切面)-- 是 切入点+通知 的结合,以后咱们自己来编写和配置的

2.AOP配置文件方式的入门

创建maven项目,坐标依赖

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- 连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!-- mysql驱动包--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><!--AOP联盟--><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version>
</dependency><!--Spring Aspects--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.0.2.RELEASE</version></dependency><!--aspectj--><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.3</version></dependency>
</dependencies>

创建Spring的配置文件,引入具体的AOP的schema约束

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

创建包结构,编写具体的接口和实现类

public class UserServiceImpl implements UserService {@Override
public void save() {//模拟异常//int a = 1/0
System.out.println("业务层:保存用户...");
}
}

将目标类配置到Spring中

<bean id="userService" class="com.qcby.service.UserServiceImpl"/>

定义切面类

package com.qcby.util;public class MyAspect {//自定义切面类 = 切入点(表达式) + 通知(增强的代码)//通知public void log(){System.out.println("增强的方法执行了。。。。");}//ProceedingJoinPoint spring提供的接口,叫连接点 //接口中proceed()方法,作用是让目标对象的方法执行public void aroundLog(ProceedingJoinPoint point){try{System.out.println("增强的方法执行了。。。。前");point.proceed()System.out.println("增强的方法执行了。。。。后");}catch(Execption e){e.stackSystem.out.println("增强的方法执行了。。。。异常");}finally{System.out.println("增强的方法执行了。。。。始终");}}
}

在配置文件中定义切面类

<bean id="myAspect" class="com.qcby.util.MyAspect"/>

在配置文件中完成aop的配置

<!--配置AOP的增强-->
<aop:config><!--配置切面 = 切入点 + 通知组成--><aop:aspect ref="myAspect"><!--前置通知:UserServiceImpl的save方法执行前,会增强--><aop:before method="log" pointcut="execution(public void com.qcby.service.UserServiceImpl.save())"/></aop:aspect>
</aop:config>

完成测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ApplicationContext2.xml")
public class Demo2 {@Autowiredprivate UserService userService;@Testpublic void run(){userService.save();}
}

3. 切入点的表达式

再配置切入点的时候,需要定义表达式,具体展开如下:

1.切入点表达式的格式如下:

  • execution([修饰符] 返回值类型 包名.类名.方法名(参数))
  • 修饰符可以省略不写,不是必须要出现的。
  • 返回值类型是不能省略不写的,根据你的方法来编写返回值,可以使用 * 代替。

2.包名,类名,方法名,参数的规则如下:

例如:com.qcby.demo3.BookDaoImpl.save()

  • 首先包名,类名,方法名是不能省略不写的,但是可以使用 * 代替
  • 中间的包名可以使用 * 号代替
  • 类名也可以使用 * 号代替,也有类似的写法:*DaoImpl
  • 方法也可以使用 * 号代替
  • 参数如果是一个参数可以使用 * 号代替,如果想代表任意参数使用 …比较通用的表达式:execution(* com.qcby.*.ServiceImpl.save(…))
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="userService" class="com.qcby.service.UserServiceImpl"/><bean id="myAspect" class="com.qcby.util.MyAspect"/><!--配置AOP的增强--><aop:config><!--配置切面 = 切入点 + 通知组成--><aop:aspect ref="myAspect"><!--前置通知:UserServiceImpl的save方法执行前,会增强--><!--<aop:before method="log" pointcut="execution(public void com.qcby.service.UserServiceImpl.save())"/>--><!--切入点的表达式execution() 固定的写法public 是可以省略不写的方法的返回值 int String 通用的写法,可以编写 * 不能省略不写的包名+类名 不能省略不写的,编写 * UserServiceImpl AccountServiceImpl方法名称 save() 可以写 *参数列表 (..) 表示任意类型和个数的参数比较通用的表达式:execution(public * cn.tx.*.*ServiceImpl.*(..))--><aop:before method="log" pointcut="execution(* com.qcby.*.*ServiceImpl.save*(..))" /> </aop:aspect></aop:config></beans>

4. AOP的通知类型

  1. 前置通知 目标方法执行前,进行增强。
  2. 最终通知 目标方法执行成功或者失败,进行增强。
  3. 后置通知 目标方法执行成功后,进行增强。
  4. 异常通知 目标方法执行失败后,进行增强。
  5. 环绕通知 目标方法执行前后,都可以进行增强。目标对象的方法需要手动执行。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="userService" class="com.qcby.service.UserServiceImpl"/><bean id="myAspect" class="com.qcby.util.MyAspect"/><!--配置AOP的增强--><aop:config><!--配置切面 = 切入点 + 通知组成--><aop:aspect ref="myAspect"><!--前置通知:UserServiceImpl的save方法执行前,会增强--><!--<aop:before method="log" pointcut="execution(public void com.qcby.service.UserServiceImpl.save())"/>--><!--AOP的通知类型前置通知:目标方法执行前,进行增强。<aop:before method="log" pointcut="execution(* com.qcby.*.*ServiceImpl.save*(..))" />最终通知:目标方法执行成功或者失败,进行增强。<aop:after method="log" pointcut="execution(* com.qcby.*.*ServiceImpl.save*(..))" />后置通知:目标方法执行成功后,进行增强。<aop:after-returning method="log" pointcut="execution(* com.qcby.*.*ServiceImpl.save*(..))" />异常通知:目标方法执行失败后,进行增强。<aop:after-throwing method="log" pointcut="execution(* com.qcby.*.*ServiceImpl.save*(..))" />环绕通知:目标方法执行前后,都可以进行增强。目标对象的方法需要手动执行。--><aop:around method="aroundLog" pointcut="execution(* com.qcby.*.*ServiceImpl.save*(..))" /></aop:aspect></aop:config></beans>

第四章:Spring的AOP技术-注解方式

1. AOP注解方式入门程序

创建maven工程,导入坐标。编写接口,完成IOC的操作。步骤略。
编写切面类
给切面类添加注解 @Aspect,编写增强的方法,使用通知类型注解声明

@Component // 把该类交给IOC去管理
@Aspect // 声明是切面类 == <aop:aspect ref="myXmlAspect">
public class MyAspectAnno {/** 配置切入点*/@Before("execution(public void com.qcby.service.OrderService.save())")public void log(){System.out.println("增强的方法执行了。。。。");}}

配置文件中开启自动代理

<aop:aspectj‐autoproxy/>

编写测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ApplicationContextanno.xml")
public class Demo3 {@Autowiredprivate OrderService orderService;@Testpublic void run(){orderService.save();}
}

2. 通知类型的注解

通知类型注解
@Before – 前置通知
@AfterReturing – 后置通知
@Around – 环绕通知(目标对象方法默认不执行的,需要手动执行)
@After – 最终通知
@AfterThrowing – 异常抛出通知

3. 纯注解的方式

纯注解的方式

@Configuration // 配置类
@ComponentScan(value = "com.qcby") // 扫描包
@EnableAspectJAutoProxy // 开启自动代理 == <aop:aspectj‐autoproxy />
public class SpringConfig {}

测试方法

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class Demo3 {@Autowiredprivate OrderService orderService;@Testpublic void run(){orderService.save();}
}

Spring THREE相关推荐

  1. spring boot项目 中止运行 最常用的几种方法

    spring boot项目 中止运行 最常用的几种方法: 1. 调用接口,停止应用上下文 @RestController public class ShutdownController impleme ...

  2. html+spring boot简单的ajax数据传输实现

    本篇讲解在前后端不分离情况下的html+spring boot的项目数据传输实现 首先,后台我写了三个接口 package com.demo.ajax.controller;import com.de ...

  3. Spring Boot整合Spring Data JPA操作数据

    一. Sping Data JPA 简介 Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套 JPA 应用框架,底层使用了 Hibernate 的 J ...

  4. Spring AOP + Redis解决重复提交的问题

    Spring AOP + Redis解决重复提交的问题 用户在点击操作的时候,可能会连续点击多次,虽然前端可以通过设置按钮的disable的属性来控制按钮不可连续点击,但是如果别人拿到请求进行模拟,依 ...

  5. Spring cloud 微服务docker容器化最佳实践

    Spring cloud 是当下最炙手可热的微服务套件,我们将介绍如何整合Docker容器达到高效快捷的构建发布 采用了dockerfile-maven-plugin插件发布镜像到远程docker主机 ...

  6. ssh(Struts+spring+Hibernate)三大框架整合-简述

    ssh(Struts+spring+Hibernate)三大框架配合使用来开发项目,是目前javaee最流行的开发方式,必须掌握: 注意: 为了稳健起见,每加入一个框架,我们就需要测试一下,必须通过才 ...

  7. Strutsw2与Spring整合流程-简述

    1.      新建WEB工程: 2.      导入struts2开发包,和资源配置文件 ① globalMessages.properties ② struts.properties 3.     ...

  8. spring Bean自动装配

    spring Bean自动装配 自动装配是使用spring满足bean依赖的一种方式. spring会在应用上下文中为某个bean寻找其依赖的bean. spring自动装配需要从两个角度来实现,或者 ...

  9. spring IOC创建对象方式

    spring IOC创建对象方式 通过无参构造来创建 验证方法: 创建实体类: public class User {private String name;public User() {System ...

  10. 第一个spring程序

    第一个spring程序: 第一步:导入jar包. 新建maven项目: <dependency><groupId>org.springframework</groupId ...

最新文章

  1. 李联宁|量子计算机:技术路线、风险及战略投资
  2. 中心极限定理_统计学基础知识3——正态分布与大数定律、中心极限定理
  3. 【电磁场实验作业】有限差分法(FDM)求解静电场电位分布
  4. Linux界面自动化测试框架不完全汇总
  5. sql-逻辑循环while if
  6. 计算机操作员初级 第1单元0202微型计算机基本操作 教学大纲,计算机操作员教学大纲...
  7. Spark 解析 : DAGScheduler中的DAG划分与提交
  8. 通过jQuery设置全局Ajax加载时呈现Loading
  9. 2019新版《龙果学院Elasticsearch顶尖高手系列(高手进阶篇教程)》
  10. 缠中说禅形态挖掘之五笔形态
  11. 解决:Intellij idea导入MyEclipse Web项目时,服务器搭建运行正常,但无法访问WebRoot下的页面
  12. 如何生成dll文件 采用VS2017生成dll文件(动态库文件)和lib文件(静态库文件)以C语言为例
  13. 微机原理_第1章 微型计算机概述
  14. Establishing Android Build Environment
  15. 深度分析小熊电器的爆红逻辑
  16. Spring开篇介绍-如果没有Spring如何对外暴露一个接口
  17. 疯狂Java讲义(九)
  18. 组合数学之递推关系(二)常系数线性齐次递推关系及其通项求解
  19. 【Unity】由预制体实例获取预制体资源及预制体资源路径
  20. 暂停更新,请到http://www.52brt.com上关注最新文章

热门文章

  1. 大学十年(一个程序员的路程)(林锐博士)《1----9》【林锐的大学10年】
  2. html表单的put方法,form表单put、delete方式提交处理
  3. Debezium报错处理系列十:Could not find existing binlog information while attempting schema only recovery sna
  4. Nodejs连接12种数据库例子集合
  5. 当 SegmentFault 遇上呼伦贝尔
  6. 闭着眼学基础python 保姆教程:组合数据类型(2)映射与集合类型
  7. dpdk 驱动移植叩开 kni 模块那些黑暗的角落
  8. POI excel行内换行
  9. GA-RPN:Region Proposal by Guided Anchoring
  10. gym 101908C Pizza Cutter (逆序对)