aop编程, 注解方式
概念:
Aop编程:
- 关注点代码与业务代码分离!(jdk/cglib代理)
关注点:
- 重复执行的代码, 也叫关注点代码!
切面:
- 关注点代码形成的类,就叫做切面
springAop编程,也叫面向切面编程!
Aop: Aspect Object Programming 面向切面编程!
举例,哪些是切面?
事务,权限控制, 日志…
切入点表达式
拦截方法,给方法所在的类,生成代理对象!
Spring在初始化容器的时候,会根据切入点表达式的规则,会符合拦截规则的方法所在的类生成代理对象!
使用Aop开发步骤:
- 引入aop 相关 jar文件
(aspectj 在spring之前,面向切面开发的公用组件)
aopalliance.jar 【spring-framework-2.5.6\lib\aopalliance】
aspectjrt.jar 【spring-framework-2.5.6\lib\aspectj】
aspectjweaver.jar 【spring-framework-2.5.6\lib\aspectj】
spring-aop-3.2.5.RELEASE.jar 【Spring3.2源码】
- 引入aop名称空间且开启aop扫描
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
- 开启aop注解
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 使用Aop相关注解
@Aspect 指定一个类为切面类
(切面类也需要实例化)
(切面类中的方法,也叫做通知)
@Before 前置通知 【在执行目标对象方法之前执行】
@After 后置通知 【在执行目标对象方法之后执行】
@AfterReturning 返回后通知 【在执行目标对象方法结束后执行, 出现异常不执行】
@AfterThrowing 异常通知 【在执行目标对象方法出现异常时候执行】
@Around 环绕通知 【环绕目标方法执行】
@Pointcut 定义一个切入点表达式变量 (后面使用这个切入点表达式的时候,直接引用方法名即可)
Spring生成代理对象的过程?
- 创建容器对象的时候, 根据“切入点表达式”拦截的类,生成代理对象;
- 如果目标对象有实现接口,使用jdk代理!
- 如果目标对象没有实现接口,使用cglib代理!
- 从容器获取代理后的对象
- 执行代理对象的方法,在运行时期,动态植入“切面”类中的“通知”!
案例
beam.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: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.xxjqr.spring01.aop_anno"></context:component-scan>
<!-- 开启aop注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
类
@Component("aop") //默认是transactionAop
@Aspect //声明一个切面类
public class TransactionAop {
// 定义一个切入点表达式变量 (后面使用这个切入点表达式的时候,直接引用方法名即可)
@Pointcut("execution(* com.xxjqr.spring01.aop_anno.UserDao.*(..))")
public void pointcut_() {
}
//【前置通知】
// 在执行业务方法,之前执行
@Before("pointcut_()")
public void beginTransaction() {
System.out.println("[前置通知] 开启事务..");
}
//【后置通知】
// 在执行业务方法,之后执行
@After("pointcut_()")
public void commit() {
System.out.println("[后置通知] 提交事务..");
}
// 【返回后通知】 在执行目标方法结束后执行, 出现异常不会执行
@AfterReturning("pointcut_()")
public void afterReturing(){
System.out.println("[返回后通知]");
}
// 【异常通知】 在执行目标方法的时候出现异常执行
@AfterThrowing("pointcut_()")
public void afterThrowing(){
System.out.println("[异常通知]");
}
// 【环绕通知】 会环绕目标方法执行
@Around("pointcut_()")
public void arroud(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("[环绕前:]");
pjp.proceed(); // 执行目标方法
System.out.println("[环绕后:]");
}
}
@Repository
public class UserDao {
public void save(){
System.out.println("已经save");
}
}
public class App {
private ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml",getClass());
@Test
public void testUserAction() {
//创建容器
UserDao dao = (UserDao) ac.getBean("userDao");
System.out.println(dao.getClass());
dao.save();
}
}