文章目录
- 一、AOP的介绍
- 1.1 基本概念
- 1.2 AOP入门
- 1.3 AOP工作流程
- 1.4 切入点表达式
- 1.5 AOP的通知类型
- 1.6 ProceedingJoinPoint
- 1.7 AOP通知获取参数数据
- 二、事物
- 2.1 基本介绍
- 2.2 事物角色
- 2.3 事物属性
- 2.4 事物的传播行为
一、AOP的介绍
1.1 基本概念
1.2 AOP入门
- 导入坐标
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency>
- 定义dao接口和实现类
@Repository
public class BookDaoImpl implements BookDao {public void save() {System.out.println(System.currentTimeMillis());System.out.println("book dao save ...");}public void update(){System.out.println("book dao update ...");}
}
- 定义通知类:定义切入点,绑定切入点与通知的关系
//通知类必须配置成Spring管理的bean
@Component
//设置当前类为切面类类
@Aspect
public class MyAdvice {//设置切入点,要求配置在方法上方@Pointcut("execution(void com.itheima.dao.impl.BookDaoImpl.update())")private void pt(){}//设置在切入点pt()的前面运行当前操作(前置通知)@Before("pt()")public void method(){System.out.println(System.currentTimeMillis());}
}
- 开启Spring对AOP注解驱动的支持
@Configuration
@ComponentScan("com.itheima")
//开启注解开发AOP功能
@EnableAspectJAutoProxy
public class SpringConfig {
}
1.3 AOP工作流程
1.4 切入点表达式
1.5 AOP的通知类型
- @after:当前通知方法在原始切入点方法后运行
- @before:当前通知方法在原始切入点方法前运行
- @AfterReturning:当前通知方法在原始切入点方法正常执行完毕后执行
- @AfterThrowing:当前通知方法在原始切入点方法运行抛出异常后执行
- @Around:当前通知方法在原始切入点方法前后运行
演示:
@Component
@Aspect
public class MyAdvice {@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Pointcut("execution(int com.itheima.dao.BookDao.select())")private void pt2(){}//@Before:前置通知,在原始方法运行之前执行
// @Before("pt()")public void before() {System.out.println("before advice ...");}//@After:后置通知,在原始方法运行之后执行
// @After("pt2()")public void after() {System.out.println("after advice ...");}//@Around:环绕通知,在原始方法运行的前后执行
// @Around("pt()")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("around before advice ...");//表示对原始操作的调用Object ret = pjp.proceed();System.out.println("around after advice ...");return ret;}// @Around("pt2()")public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {System.out.println("around before advice ...");//表示对原始操作的调用Integer ret = (Integer) pjp.proceed();System.out.println("around after advice ...");return ret;}//@AfterReturning:返回后通知,在原始方法执行完毕后运行,且原始方法执行过程中未出现异常现象
// @AfterReturning("pt2()")public void afterReturning() {System.out.println("afterReturning advice ...");}//@AfterThrowing:抛出异常后通知,在原始方法执行过程中出现异常后运行@AfterThrowing("pt2()")public void afterThrowing() {System.out.println("afterThrowing advice ...");}
}
1.6 ProceedingJoinPoint
@Component
@Aspect
public class ProjectAdvice {//配置业务层的所有方法@Pointcut("execution(* com.itheima.service.*Service.*(..))")private void servicePt(){}//@Around("ProjectAdvice.servicePt()") 可以简写为下面的方式@Around("servicePt()")public void runSpeed(ProceedingJoinPoint pjp){//获取执行签名信息Signature signature = pjp.getSignature();//通过签名获取执行操作名称(接口名)String className = signature.getDeclaringTypeName();//通过签名获取执行操作名称(方法名)String methodName = signature.getName();long start = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {pjp.proceed();}long end = System.currentTimeMillis();System.out.println("万次执行:"+ className+"."+methodName+"---->" +(end-start) + "ms");}
}
1.7 AOP通知获取参数数据
- 获取参数
- 获取返回值
- 获取异常
二、事物
2.1 基本介绍
- 在业务层接口的方法或者接口类(表示里面所有方法都事务管理)上添加事务管理注解@Transactional
public interface AccountService {/*** 转账操作* @param out 传出方* @param in 转入方* @param money 金额*///配置当前接口方法具有事务@Transactionalpublic void transfer(String out,String in ,Double money) ;
}
- 设置事务管理器,创建一个事务管理的bean,例如:创建一个管理数据库的事物bean
public class JdbcConfig {@Value("${jdbc.driver}")private String driver;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String userName;@Value("${jdbc.password}")private String password;@Beanpublic DataSource dataSource(){DruidDataSource ds = new DruidDataSource();ds.setDriverClassName(driver);ds.setUrl(url);ds.setUsername(userName);ds.setPassword(password);return ds;}//配置事务管理器,mybatis使用的是jdbc事务@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource){DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();transactionManager.setDataSource(dataSource);return transactionManager;}
}
- 开启注解式事务驱动
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
//开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
}
2.2 事物角色
2.3 事物属性
当代码抛出IOException异常时,事物不会回滚,因此我们需要设置@Transactional(rollbackFor={IOException.class})来保证遇到IO异常时事物回滚。
2.4 事物的传播行为
1.REQUIRES_NEW解读:
由于多个事物协调员由一个事物管理员管理,当一个事物失败时,其他事物也不能执行;当我们需要保证一个事物协调员不会受其他事物影响时,设置@Transactional(propagation=Propagation.REQUIRES_NEW)。
2.REQUIRES_NEW应用场景:
当我们在转账时,无论成功失败,都需要向数据库中写入日志,首先把转账与写日志写进一个转账Service的方法中,并加上事务管理@Transactional;然后我们就需要在日志的Service接口的方法中加入@Transactional(propagation=Propagation.REQUIRES_NEW)。
日志接口与实现类:LogService、LogServiceImpl
public interface LogService {//propagation设置事务属性:传播行为设置为当前操作需要新事务@Transactional(propagation = Propagation.REQUIRES_NEW)void log(String out, String in, Double money);
}@Service
public class LogServiceImpl implements LogService {@Autowiredprivate LogDao logDao;public void log(String out,String in,Double money ) {logDao.log("转账操作由"+out+"到"+in+",金额:"+money);}
}
转账接口和实现类:AccountService、AccountServiceImpl
public interface AccountService {//rollback:设置当前事务参与回滚的异常,默认非运行时异常不参与回滚
// @Transactional(rollbackFor = IOException.class)@Transactionalpublic void transfer(String out,String in ,Double money) throws IOException;
}@Service
public class AccountServiceImpl implements AccountService {@Autowiredprivate AccountDao accountDao;@Autowiredprivate LogService logService;public void transfer(String out,String in ,Double money) {try{accountDao.outMoney(out,money);int i = 1/0;accountDao.inMoney(in,money);}finally {logService.log(out,in,money);}}}