1.Aop
- 前置通知【@Before】:在目标方法执行之前执行的功能
- 后置通知【@After】: 在目标方法执行之后,无论目标方法能否正常执行成功,后置通知都会执行
- 返回通知【@AfterReturning】: 在目标方法执行之后,在目标方法执行成功的前提下,返回通知才执行
- 异常通知【@AfterThrowing】:在目标方法执行之后,在目标方法出现异常的情况下,异常通知才会执行
- 环绕通知【@Around】:以一抵四
1.1切面中的五种通知[方法]
@Component
@Aspect//这表示当前类是一个切面类
public class LogAspect {
//前置通知
@Before("execution(public int com.offcn.p1.service.CaculatorImpl.*(int, int))")
public void printBeforeLog() {
System.out.println("method before.........");
}
//后置通知
@After("execution(public int com.offcn.p1.service.CaculatorImpl.*(int, int))")
public void printAfterLog() {
System.out.println("method after.........");
}
//返回通知
@AfterReturning("execution(public int com.offcn.p1.service.CaculatorImpl.*(int, int))")
public void printAfterReturnLog() {
System.out.println("method afterReturning.........");
}
//异常通知
@AfterThrowing("execution(public int com.offcn.p1.service.CaculatorImpl.*(int, int))")
public void printAfterThrowingLog() {
System.out.println("method afterThrowing.........");
}
}
1.2通知的底层结构
通知的底层结结构:
try {
try {
//1.前置通知
//2.目标方法
}finally {
//3.后置通知
}
//4.返回通知
}catch (Throwable e) {
//5.异常通知
}
1.3切入点表达式
作用:定位目标方法【被拓展的方法】
语法:execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名] ([参数列表]))
最复杂【最精确】:execution(public int com.offcn.p1.service.CaculatorImpl.add(int,int))
最简洁【最模糊】:execution(* *.*(..))
切入点表达式的重用:
@Pointcut("execution(* *.*(..))")
public void myPointCut() {}
//前置通知
@Before("myPointCut()")
public void printBeforeLog() {
System.out.println("method before.........");
}
切入点表达式支持:&& || !运算符。
1.4从通知中获取目标方法的信息
前置通知
@Before("execution(public int com.offcn.p1.service.CaculatorImpl.add(int, int)) || execution(public int com.offcn.p1.service.CaculatorImpl.substract(int, int))")
public void printBeforeLog(JoinPoint joinPoint) {
//1.获取目标方法签名
String name=joinPoint.getSignature().getName();
//2.获取参数列表
Object[] args = joinPoint.getArgs();
List<Object> asList = Arrays.asList(args);
System.out.println("前置通知,获取目标方法名:"+name+",传递过来的参数列表为:"+asList);
}
返回通知:
@AfterReturning(value="myPointCut()",returning="result")
public void printAfterReturnLog(Object result) {
System.out.println("method afterReturning........."+result);
}
要求:
- 给@AfterReturning加一个returning属性
- returning属性值一定要和返回通知的参数名一致,参数类型最好为Object类型
异常通知:
@AfterThrowing(value="myPointCut()",throwing="ex")
public void printAfterThrowingLog(Throwable ex) {
System.out.println("method afterThrowing.........,异常信息为:"+ex.getMessage());
}
要求:
- @AfterThrowing加一个throwing属性
- throwing属性值必须和异常通知的参数名一致,参数类型最好是Throwable类型
1.5环绕通知实现事务切面
事务:
Connection conn=JdbcUtils.getConnection();
Try{
Conn.setAutoCommit(false);//开启事务
//调用dao层发送sql语句
Conn.commit(); //提交事务
}catch(Exception ex){
Conn.rollback();//回滚
}finally{
Conn.close(); //释放连接
}
@Component
@Aspect
public class TransactionAspect {
//环绕通知
@Around("com.offcn.p1.service.LogAspect.myPointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = null;
try {
try {
//1.执行前置通知----->获取数据库连接、Conn.setAutoCommit(false);//开启事务
//执行目标方法
result = joinPoint.proceed();
}finally {
//2.后置通知
}
//3.返回通知----》 提交事务 conn.commit();
}catch (Exception e) {
// 4.异常通知
e.printStackTrace(); //回滚事务conn.rollback();
}
return result;
}
}
1.6多切面情况下的切面优先级问题
多切面情况下,切面的优先级是靠切面上的@Order注解决定的,value值越小,优先级越高。
如果切面类上都不加注解,切面的优先级是靠着切面类的类名。
1.7多切面情况下的各个通知优先级问题
第一种:目标方法能够正常执行
第二种:目标方法出现异常,内层切面抛出异常
第二种:目标方法出现异常,内层切面不抛出异常!
1.8基于xml的aop配置
<!-- 1.将被代理类和切面类对象放入到容器中 -->
<bean id="caculatorImpl" class="com.offcn.p1.service.CaculatorImpl"></bean>
<bean id="logAspect" class="com.offcn.p1.service.LogAspect"></bean>
<bean id="transactionAspect" class="com.offcn.p1.service.TransactionAspect"></bean>
<aop:config>
<!-- 指定切入点表达式 -->
<aop:pointcut expression="execution(public int com.offcn.p1.service.CaculatorImpl.*(..))" id="myPointCut"/>
<!-- 指定切面 -->
<aop:aspect ref="logAspect" order="10">
<aop:before method="printBeforeLog" pointcut-ref="myPointCut"/>
<aop:after method="printAfterLog" pointcut-ref="myPointCut"/>
<aop:after-returning method="printAfterReturnLog" returning="result" pointcut-ref="myPointCut"/>
<aop:after-throwing method="printAfterThrowingLog" throwing="ex" pointcut-ref="myPointCut"/>
</aop:aspect>
<aop:aspect ref="transactionAspect" order="9">
<aop:around method="around" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
1.9JdbcTemplate介绍
Spring的JdbcTemplate实际上就是Spring框架对原生Jdbc的简单封装,类似于我们JavaWeb部分学过的DBUtils工具类,用来完成对数据表数据的增删改查操作。
第一步:导入jar包
第二步:在spring的配置文件中配置JdbcTemplate
第三步:在Dao层注入JdbcTemplate
第四步:在Dao层方法使用JdbcTemplate对数据表进行增删改查操作
@Repository
public class EmployeeDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(Employee employee) {
String sql="insert into employee(emp_name,salary) values(?,?)";
jdbcTemplate.update(sql, employee.getEname(),employee.getSalary());
}
}