Spring AOP对于刚开始学习spring的同学来说有点难以理解,我刚工作的时候都没怎么理解,现在稍微理解了一点,所以在这里我将用嘴简单的例子,最通俗易懂的话语来说出我的理解,可能由于我对Spring AOP理解还不够深入,有些地方理解还有误,各位大神要是看出来了请指正。
1.AOP介绍
AOP就是面向切面编程,是面向对象编程的一种补充。如果面向对象编程中产生的一个个对象,看成是一个个珍珠的话,那么面向切面编程中的切面可以说是串起每个珍珠的细线了。下面是AOP的一些基本概念,可能和你以前看到的不太一样,也不是那么准确,但非常好理解(呵呵,因为是我自己的一些理解)。
比如有老师,学生这两个类,学生有读书,玩游戏这两个方法,老师有上课,管理学生这两个方法。但我想记录老师和学生的一举一动。如果没有面向切面编程的话,可能我们我们会将记录动作这个方法加在学生和老师这两个类里面的每个方法前面,这样就会导致大量的代码冗余,也会造成记录动作和所做的动作之间的关系的耦合度非常之高。
如果用面向切面编程的思想来解决这一问题的话,我们可以将记录动作这个行为给封装起来产生一个新的类。再在学生或是老师有动作要发生的时候,调用记录动作这个类里面的记录动作方法。有人要问了,你这样和前面的有什么区别,现在看确实没什么区别,但是当我们将这个调用记录动作这个方法交给程序自己来完成,不需要我们一个个手动添加的时候是不是会觉得很方便,而且我们想要修改记录动作的效果,比如想记录慢动作,那我们只需修改一个地方,这样看起来是不是很方面,而且他俩者之间的关联性也降低了。
前面举的一个例子只是为了更好的理解AOP里面的那些概念,当把AOP里面的一个个概念摆出来的时候,你即使背住了它,也很难将这些概念和我们实际运用联系在一起。
方面:就是将那些与业务无关,却为业务逻辑模块所共同调用的逻辑封装组成一个新的模块,这个模块就可以看成是哟个方面。上面的例子里记录动作的这个类就可以看成是一个方面。
通知: 在切面类中,声明对业务方法做额外处理的方法。业务类中指定的方法,作为切面切入的点。各种类型的通知包括“around”、“before”和“throws”通知。可以将记录动作里面的记录动作这个方法看做是一个通知。
切入点:业务类中指定的方法,作为切面切入的点,可以将学生读书这个动作作为一个切入点,因为学生在做读书这个动作的时候会记录这个动作。
目标对象:要被切面横切的对象。比如学生或老师这两个对象都可以看做是一个目标对象。
代理对象:可以将织入了通知的目标对象形成新的对象看成是代理对象。这个对象是实际中不存在的,是spring容器生成的。比如学生这个对象本来只有读书和玩游戏这两个动作的,但是要记录学生的这两个动作,那么在这两个动作的前面都会加上记录动作这个方法,这就生成了一个新的对象,可以将这个看成是代理对象。
还有一点:当目标对象不是某个接口的实现的话,会用cglib代理,否则就会使用jdk动态代理
2.代码:
package spring.test;
public interface Student {
public void selfIntruction(String name,String home);
public void startGoClass();
public void endGoClass();
}
package spring.test;
public class StudentImpl implements Student{
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public void selfIntruction(String name,String home){
System.out.println("学生:大家好。我叫"+name+",来自"+home);
}
public void startGoClass(){
teacher.sartClass();
System.out.println("学生:我要开始认真听讲了");
teacher.classing();
}
public void endGoClass(){
System.out.println("学生:快要下课了");
teacher.endClass();
}
}
package spring.test;
public class Teacher {
public void selfIntruduction(){
System.out.println("老师:我是李易峰,在三合中学教数学");
}
public void sartClass(){
System.out.println("老师:同学们开始上课了");
}
public void classing(){
System.out.println("老师:同学们:1+1=?");
}
public void endClass(){
System.out.println("老师:同学们可以下课休息了");
}
}
package spring.test;
/**
*方面类
* @author user
* 2015-07-09
*
*/
public class aopDAO {
/**
* 通知方法
*/
public void doBefore(){
System.out.println("今天的天气真好!");
}
public void doAfter(){
System.out.println("今天终于忙完了,可以休息了");
}
public void doAround(){
System.out.println("虽然忙还是要吃饭的!");
}
}
applicationContext.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:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<bean id="teacher" class="spring.test.Teacher"></bean>
<bean id="student" class="spring.test.StudentImpl">
<property name="teacher" ref="teacher"></property>
</bean>
<!-- 定义方面 -->
<bean id="aopdao" class="spring.test.aopDAO"></bean>
<aop:config>
<!--
切入点,定义目标 execution(* spring.test.*.*(..))表示spring.test包下的所有类的所有方法,
第二个*代表所有类,第三个*代表着这个类的所有方法,(..)代表传入方法的参数为0个或多个
-->
<aop:pointcut expression="execution(* spring.test.*.*(..))" id="pointcut"/>
<aop:aspect id="testAspect" ref="aopdao">
<!-- 通知 -->
<aop:before method="doBefore" pointcut-ref="pointcut"/>
<aop:after method="doAfter" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
<!--
整体解读就是当程序在执行spring.test包下的某个类里面的某个方法时,程序会先执行aopDAO类里面的doBefore方法,
当pring.test包下的某个类里面的某个方法执行完毕后,程序还会执行aopDAO类里面的doAfter方法,够直观了吧,我相信你一定懂了
-->
</beans>
package spring.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class springTest {
public static void main(String[] args){
String conf = "/spring/test/applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(conf);
Student student = context.getBean("student",Student.class);
student.startGoClass();
System.out.println("***************************************");
Teacher teacher = context.getBean("teacher",Teacher.class);
teacher.sartClass();
}
}
最后运行的结果:
老师:同学们开始上课了
今天终于忙完了,可以休息了
学生:我要开始认真听讲了
今天的天气真好!
老师:同学们:1+1=?
今天终于忙完了,可以休息了
今天终于忙完了,可以休息了
***************************************
今天的天气真好!
老师:同学们开始上课了
今天终于忙完了,可以休息了
如果你看了这篇文章觉得对你理解spring aop有用,请看在作者饿着肚子的情况下点个赞吧,下班了,回去咯。