spring aop 是面向切面编程,底层也是使用代理模式来进行实现的 在spring aop 如果是实现接口方式 使用 jdk 提供的代理模式,如果继承的方式,就使用cglib来实现代理模式。aop来实现代码的分离,以及动态来执行某些操作(方法)。
一些概念 被代理对象:只包含核心代码的对象。 代理对象:对被代理对象增强的对象。 连接点(joinpoint):指核心代码中的所有方法。 切入点(pointcut):指核心代码中需要增强的方法。 通知(advice):指事务、日志等代码,增强代码。 织入(weaving):是一个动作,指将增强代码加入到切入点中执行。 切面(aspect):通知+切入点小案例 1.添加依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--用于来解析切入点表达式--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> 编写代理对象类(核心代理业务类)、增强类xml文件中添加约束,实例化代理对象和增强对象,配置切面 <?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: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 id="ser" class="com.fyj.service.impl.UserService"></bean> <!-- 增强对象--> <bean id="aop" class="com.fyj.springaop.Aop"></bean> <!-- <aop:config>--> <!-- <aop:aspect ref="aop">--> <!-- <aop:after method="show1" pointcut="execution(public void com.fyj.service.impl.UserService.core())"></aop:after>--> <!-- </aop:aspect>--> <!-- </aop:config>--> <!-- 可以将pointcut提取出来--> <aop:config> <aop:pointcut id="pc" expression="execution(public void com.fyj.service.impl.UserService.core())"/> <aop:aspect ref="aop"> <aop:before method="show1" pointcut-ref="pc"></aop:before> <aop:after-returning method="show2" pointcut-ref="pc"></aop:after-returning> <aop:after-throwing method="show3" pointcut-ref="pc"></aop:after-throwing> <aop:after method="show4" pointcut-ref="pc"></aop:after> </aop:aspect> </aop:config>execution(public void com.fyj.service.impl.UserService.core()中写的是代理对象中被增强的方法,public可以省略 void、路径名和方法名可以用*代替 4.获得实体bean执行被增强的方法
@org.junit.Test public void test1(){ ApplicationContext app = new ClassPathXmlApplicationContext("aop.xml"); UserService userService = (UserService) app.getBean("ser"); userService.core(); } spring中四种增强前置增强 ==>在核心业务代码前面执行操作aop:before
后置增强 ==>在核心代码的后面执行的操作 after-returning
异常增强 ==>核心操作发生异常执行的操作 aop:after-throwing
最终增强 ==>最后执行的代码 aop:after
环绕增强实际是自定义的增强 xml中配置
<aop:config> <aop:aspect ref="aop"> <aop:around method="show" pointcut="execution(public void com.fyj.service.TestService.core())"></aop:around> </aop:aspect> </aop:config>增强类
public void show(ProceedingJoinPoint point){ try { System.out.println("before"); //执行代理方法 point.proceed(point.getArgs()); System.out.println("after"); } catch (Throwable throwable) { System.out.println("throw"); }finally { System.out.println("finally"); } }使用注解来实现面向切面开发 xml,中删除切面的配置信息,添加
<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"> <context:component-scan base-package="com.fyj"></context:component-scan> <aop:aspectj-autoproxy /> </beans>增强对象中
@Component(value = "tu2") public class TestUtils2 { @Pointcut(value = "execution(public void com.fyj.service.TestService2.core())") public void show(){} @Before("show()") public void before(){ System.out.println("before"); } }@Pointcut指定了切点,show()方法是没有任何意义的。@Before(“show()”)设置了前置增强。同样的注解还有@AfterReturning@AfterThrowing@After@Around 环绕增强
spring关于事务的操作 编程式事务:直接在java代码中添加事务,没有动态代理之前最原始方式 声明式事务:采用spring aop的思想来进行事务管理,事务代码与核心代码进行分离 spring中的事物控制主要通过以下三个api来实现: 1.PlatformTransactionManager 负责事务的管理,是个接口,其子类负责具体工作
类或方法描述DataSourceTransactionManagerPlatformTransactionManager的实现类,用于使用标准数据源时的事务管理TransactionStatus getTransaction(TranstionDefinition def)获取事务状态信息void commit(TransactionStatus status)提交事务void rollback(TransactionStatus status)回滚事务2.TransactionDefinition 定义事务的相关参数 规定事务隔离级别,事务传播行为
隔离级别描述TRANSACTION_READ_UNCOMMITTED读未提交,存在问题:脏读TRANSACTION_READ_COMMITTED读已经提交 ,存在问题:可重复读TRANSACTION_REPEATABLE_READ可重复读 ,存在问题:幻读RANSACTION_SERIALIZABLE可串化,解决以上所有的问题:使用数据库(同步锁)锁来进行操作事务传播行为是指当一个业务方法被另一个事务方法调用时,如何进行事务控制 3.TransactionStatus 代表事务运行的实时状态
方法描述boolean isNewTransaction()是否是新事务boolean hasSavepoint()是否有回滚点void setRollbackOnly()设置回滚事务boolean isRollbackOnly()是否是回滚事务void flush()刷新事务boolean isCompleted()事务是否完成即事务管理器读取事务参数进行事务管理,会产生事务的运行状态
基于xml文件进行事务管理 需要使用AOP来进行事务控制,spring提供事务代码(增强类),我们需要去编写业务代码和配置切面 transfer是需要配置事务的方法 @Component(value = "ser") public class UserServiceImpl implements UserService { @Autowired @Qualifier(value = "dao") private UserDao userDao; // @Transactional(propagation = REQUIRED) public void transfer(User user1, User user2) { userDao.update(user1); int num = 0/0; userDao.update(user2); } } <!-- 设置事务管理对象--> <bean id="tvm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="ds"></property> </bean> <!-- 设置(环绕)通知--> <tx:advice transaction-manager="tvm" id="tva"> <tx:attributes> <!-- 规定待匹配的方法,以及事务设置--> <tx:method name="transfer" propagation="REQUIRED"/> <!-- 设置*则会匹配所有的方法--> <!-- <tx:method name="*" propagation="REQUIRED"></tx:method>--> </tx:attributes> </tx:advice> <!-- 设置切面--> <aop:config> <aop:pointcut id="pc" expression="execution(* com.fyj.service.impl.UserServiceImpl.*(..))"/> <aop:advisor advice-ref="tva" pointcut-ref="pc"></aop:advisor> </aop:config> <!-- <tx:annotation-driven transaction-manager="tvm"></tx:annotation-driven>--> @org.junit.Test public void Test1(){ ApplicationContext app = new ClassPathXmlApplicationContext("User.xml"); UserService service = (UserService) app.getBean("ser"); User user =new User(1,"a",50); User user1 = new User(2,"b",100); service.transfer(user,user1); } }验证:当执行到 service中的 int num = 0/0; 发生运行时异常,userDao.update(user1);的操作并生效。将 int num = 0/0;注释,再次运行userDao.update(user1)和userDao.update(user2)都生效。 配置时也可以使用注解的方式 service中的注解 xml中不需要在配置切面,开启事务的注解