Spring Aop
1,概念
AOP,面向切面编程,实际上对OOP(面向对象编程)的一个补充。
在面向对象编程的软件设计中,设计者会让不同的类去实现不同的方法,代码就分散到不同的类里面去了。降低了代码的复杂程度,提高了类的重用性。
但是如果不同的类里面方法都需要实现某个功能,例如日志功能,那就必须在每个类都添加日志内容。如果将这个代码抽出来,单独建一个类,这样有提高了耦合。
所以,这种在运行时候,将代码切入到指定类的指定方法,指定位置的的编程思想就是面向切面编程。
2,AOP 术语
Joinpoint(连接点):程序执行时的某个特定的点,在Spring中就是某一个方法的执行 。
Pointcut(切点):spring中AOP的切点就是指一些方法的集合,而这些方法是需要被增强、被代理的。一般都是按照一定的约定规则来表示的,如正则表达式等。切点是由一类连接点组成。
Aspect(切面):切面就是切点和连接点的结合。
Advice(通知):就是在指定切点上要干些什么。
Advisor(通知器):其实就是切点和通知的结合 。
<aop:pointcut expression = " execution(*com.hella.aop.*.study(..))" id = ”study”/>
第一个空格前是说明ret-type-pattern,空格后是说明name-pattern(param-pattern),具体说明如下:
第一个*(ret-type-pattern), 表示任意返回值类型
第二个和第三个*(name-pattern), 第二个包名通配,第三个方法名通配
最后二个.. 表示通配方法可以有0个或多个参数
3,通知的类型
前置通知:在一个方法执行之前,执行通知。
后置通知:在一个方法执行之后,不考虑其结果,执行通知。
返回后通知:在一个方法执行之后,只有在方法成功完成时候,才能执行通知。
抛出异常后通知:在一个方法执行之后。只有在方法退出抛出异常时,才能执行通知。
环绕通知:在建议方法调用之前和之后,执行通知。
4,Aop 实现
方法1:基于XML 实现
public interface Student {
public void study();
public void play();
}
public class ForeignStudent implements Student {
@override
public void study(){
system.out.println("foreign students will study");
}
@override
public void play(){
system.out.print("foreign students will play");
}
}
public class ChineseStudent implements Student{
@override
public void study(){
system.out.print("chinese students will study");
}
@override
public void play(){
system.out.print("chinese students will play");
}
}
定义切面类:
public class AopAspect {
public void beforeStudy(){
system.out.print("wash hand");
}
public void beforePlay(){
system.out.print("put on sport shoes");
}
public void afterPlay(){
system.out.print("wash hand");
}
}
在XML 配置文件中,首先需要实例化目标对象。
<bean id = "foreignStudent" class = "com.hella.aop.ForeignStudent"></bean>
<bean id = "chineseStudent" class = "com.hella.aop.chineseStudent"></bean>
然后,需要实例化切面类。
<bean id = "aopAspect" class = "com.hella.aop.AopAspect"></bean>
其次,配置切入对象(point cut),一些方法的集合
<aop:config>
<aop:pointcut expression = " execution(*com.hella.aop.*.study(..))" id = "study"/> //要切入的对象
<aop:pointcut expression = "execution(*com.hella.aop.*.play(..))" id = "play"/>
<aop:aspect id = "ha" ref = "aopAspect" >
<aop:before method="beforeStudy()" pointcut-ref="study"/><!-- 之前通知 -->
<aop:before method="beforePlay()" pointcut-ref="play"/><!-- 之前通知 -->
<aop:after method="afterPlay()" pointcut-ref="play"/><!-- 之后通知 -->
// <aop:after-returning 返回后通知
// <aop:after-throwing 异常通知
// <aop:around 环绕通知
</aop:aspect>
</aop:config>
测试:
public class test {
public static void main(String[] args){
ApplicationContext context = new classPathApplicationContext("beans.xml");
Student s = (Student )context.getBean("foreignStudent");
s.study();
s.play();
Student s = (Student) Context.getBean("chineseStudent");
s.study();
s.play();
}
}
打印结果:wash hand
foreign student will study
put on sport shoes
foreign student will play
wash hand
wash hand
chinese student will study
put on sport shoes
chinese student will play
wash hand
方法2:基于注解
public interface Student {
public void study();
public void play();
}
@Component //自动扫描并且实例化
public class ForeignStudent implements Student {
@override
public void study(){
system.out.println("foreign students will study");
}
@override
public void play(){
system.out.print("foreign students will play");
}
}
@Component //自动扫描并且实例化
public class ChineseStudent implements Student{
@override
public void study(){
system.out.print("chinese students will study");
}
@override
public void play(){
system.out.print("chinese students will play");
}
}
定义切面类:
@Aspect //声明该类是切面类
@Component //自动扫描并且实例化
public class AopAspect {
@Before(“execution(*.com.hella.aop.*study(..))”)
public void beforeStudy(){
system.out.print("wash hand");
}
@Before("execution(*.com.hella.aop.*.play(..))")
public void beforePlay(){
system.out.print("put on sport shoes");
}
@After("execution(*.com.hella.aop.*.play(..))")
public void afterPlay(){
system.out.print("wash hand");
}
}
//@AfterReturnning 返回通知
//@AfterThrowing 抛出异常通知
//@Around 环绕通知
在配置文件Bean.xml中,首先需要引入aop的命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
然后,
<!-- 自动扫描包下的类,并将其实例化。多个包之间用,隔开 -->
<context:component-scan base-package="com.hella.aop"></context:component-scan>
<!-- 配置文件中启动AspectJ的注解功能 ,默认是false,要将其改为true -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
测试:
public class test {
public static void main(String[] args){
ApplicationContext context = new classPathApplicationContext("beans.xml");
Student s = (Student )context.getBean("foreignStudent");
s.study();
s.play();
Student s = (Student) Context.getBean("chineseStudent");
s.study();
s.play();
}
}
打印结果:wash hand
foreign student will study
put on sport shoes
foreign student will play
wash hand
wash hand
chinese student will study
put on sport shoes
chinese student will play
wash hand