JAVA学习日志3-6(spring AOP)

tech2024-10-19  14

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中不需要在配置切面,开启事务的注解

最新回复(0)