Spring笔记(2)
一、AOP简介
1.概念:
-
面向切面编程(Aspect-Oriented Programming),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。
-
AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。
2.作用
在程序运行期间,在不修改源码的情况下对方法进行功能的增强
- 日志记录,性能统计,安全控制,事务处理,异常处理等等wn及扩展
3.底层实现
AOP的动态代理技术
JDK代理
基于接口的动态代理技术
cglib代理
基于父类动态代理技术
4.知识要点
aop:面向切面编程
aop底层实现:基于jdk的动态代理和基于cglib的动态代理
aop的重点概念:
- Pointcut(切入点):被增强的方法
- Adivce(通知/增强):封装增强业务逻辑的方法
- Aspect(切面):切点+通知
- Weaving(织入):将切点与通知结合的过程
二、基于XML的AOP开发
1.快速入门
步骤
-
添加坐标,spring-context 和 aop
<!-- spring-context--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency> <!-- aop--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> </dependencies>
-
创建目标接口并实现目标接口(连接点,切入点)
//接口类 public interface TargetInterface { public void save(); } //实现类 @Override public void save() { System.out.println("saving.."); }
-
创建切面类(内写增强方法)
//切面类 public class MyAspect { public void before(){ System.out.println("前置增强。。。"); } }
-
创建applicationContext.xml文件,并将目标对象和切面类注入
<!-- 目标对象--> <bean id="target" class="AopLearn.Target"></bean> <!-- 切面对象--> <bean id="myAspect" class="AopLearn.MyAspect"></bean>
-
引入aop命名空间
xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
-
配置织入,告诉spring框架,哪些方法(切点)需要进行那些增强(前置、后置)
<aop:config> <!-- 声明切面--> <aop:aspect ref="myAspect"> <!-- 声明切点和通知--> <aop:before method="before" pointcut="execution(public void AopLearn.Target.save())"> </aop:aspect> </aop:config>
2.切点表达式
表达式语法:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
注:
- 返回值类型、包名、类名、方法名可以使用星号*代表任意
- 访问修饰符可以省略
- 包名与类名之间一个点.代表当前包下的类,两个点表示当前包及其子包下的类
- 参数列表可以使用两个点…示任意个数,任意类型的参数列表
常用:
excution( com itheima.app. .* (..));**
任意返回值 it黑马aop包下的 任意类的 任意方法
抽取(易于维护 ):
<!-- 抽取切点表达式-->
<aop:pointcut id="myPointcut" expression="execution(* AopLearn.*.*(..))"/>
<!-- 使用抽取的切点表达式-->
<aop:before method="before" pointcut-ref="myPointcut"/>
3.通知的类型
-
前置通知:调用目标组件前,调用方面组件(before)
-
<aop:before method="before" pointcut="execution(public void AopLearn.Target.save())"></aop:before>
-
后置通知:调用目标组件后,调用方面组件(after-returning)
-
最终通知:调用目标组件后,在finally里调用方面组件(after)
-
异常通知:目标组件发生异常时,调用方面组件。(after-throwing)
-
环绕通知:调用目标组件前、后,分别调用一次方面组件。(around)
三、基于注解的AOP开发
1.快速入门
-
创建目标接口和目标类
-
创建切面类
-
将目标类和切面类的创建权交给Spring管理,并设置切面类标识。 (生成bean)
//实现bean的注入 @Component("target") public class Target implements TargetInterface { @Override public void save() { System.out.println("saving.."); } } //实现bean的注入 @Component("myAspect") //配置为切面类 @Aspect public class MyAspect { //注解配置织入关系 @Before("execution(* Annotation.*.*(..))") public void before(){ System.out.println("anno前置增强。。。"); } }
-
在切面类中使用注解配置织入关系
public class MyAspect { //注解配置织入关系 @Before("execution(* Annotation.*.*(..))") public void before(){ System.out.println("anno前置增强。。。"); } }
-
创建context命名空间
-
在配置文件中开启组件扫描和AOP的自动代理
<!-- 开启组件扫描--> <context:component-scan base-package="Annotation"/> <!-- aop自动代理--> <aop:aspectj-autoproxy/>
-
测试
@Test public void test02(){ ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext-anno.xml"); TargetInterface target = app.getBean(TargetInterface.class); target.save(); }
2.切点表达式
抽取
/**
* 定义切点表达式
*/
@Pointcut("execution(* Annotation.*.*(..))")
public void pointcut(){}
配置织入关系
@Before("pointcut()")
public void before(){
System.out.println("anno前置增强。。。");
}
3.通知的类型
-
@Before --- 前置通知
-
@AfterReturning --- 后置通知
-
@Around --- 环绕通知(目标对象默认不执行,需要手动执行)
-
@After --- 最终通知
-
@AfterThrowing --- 异常抛出通知
4.注意
使用@Aspect标注切面类
一定配置aop自动代理
<!-- aop自动代理-->
<aop:aspectj-autoproxy/>