前几天我们回顾了静态代理,jdk动态代理,cglib代理,而aop的实现就是依靠动态代理实现,如果我们仅仅去看spring的api,我们理解一些概念会很困难,但我们清楚了动态代理后,理解这些概念就会很轻松!下面我们来看一下aop中几个核心的概念:
这样来看概念,的确比去看文档轻松很多吧,我们可以去看spring的api的上的例子,一些概念就不太建议去按照spring的api上去理解。
下面我们通过例子来看aop中的一些通知:
首先创建一个接口:PersonDao:
public interface PersonDao {
public String savePerson();
}
创建接口的实现类:
public class PersonImpl implements PersonDao{
@Override
public String savePerson() {
// TODO Auto-generated method stub
int a = 1/0;
System.out.println("SavePerson............");
return "yss";
}
}
然后创建一个事务:Transcation:即一个切面:
public class Transcation {
/**
* 前置通知:在目标方法执行之前
* 后置通知:在目标方法执行之后
* 参数:连接点
*/
//前置通知
public void beginTranscation(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("连接点的名称:"+methodName);
System.out.println("目标类:"+joinPoint.getTarget().getClass());
System.out.println("beginTranscation....");
}
/*
*val要和returning中的参数保持一致,获取目标方法的返回值
*/
public void commit(JoinPoint joinPoint,Object val) {
System.out.println("commit..........");
System.out.println("目标方法的返回值:"+val);
}
/*最终通知
*
* */
public void finallyMethod() {
System.out.println("finallyMethod/..");
}
/*异常通知
* 接收目标方法抛出的异常 第二个参数和配置文件中的throwing保持一致
* */
public void thorwingMethod(JoinPoint joinPoint,Throwable ex) {
System.out.println(ex.getMessage());
}
/*环绕通知
* processdingJoinPoint.proceed()如果在环绕通知中不写,则目标方法不再执行
* 即环绕通知可以控制目标方法执行
* */
public void aroundMethod(ProceedingJoinPoint processdingJoinPoint) throws Throwable {
System.out.println("=====环绕");
processdingJoinPoint.proceed(); //调用目标方法
}
}
接下来我们仔细看一下写的这些方法的作用:
前置通知: beginTranscation:,在目标方法执行之前执行
参数是JoinPoint 通过这个参数,
我们可以获取连接点(目标方法)的名称和目标类。
通过joinPoint.getSignature().getName();可以获取连接点(目标方法)的名称
通过joinPoint.getTarget().getClass()可以获取目标类的class
public void beginTranscation(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("连接点的名称:"+methodName);
System.out.println("目标类:"+joinPoint.getTarget().getClass());
System.out.println("beginTranscation....");
}
后置通知:comomit:在目标方法执行之后执行
public void commit(JoinPoint joinPoint,Object val) {
System.out.println("commit..........");
System.out.println("目标方法的返回值:"+val);
}
参数是JoinPoint joinPoint和Object value。
其中参数joinPoint为连接点,参数value是目标方法的返回值。
异常通知 :接收目标方法抛出的异常 第二个参数和配置文件中的throwing保持一致
public void thorwingMethod(JoinPoint joinPoint,Throwable ex) {
System.out.println(ex.getMessage());
}
最终通知 finallyMethod:无论目标方法是否抛出异常,都将执行
public void finallyMethod() {
System.out.println("finallyMethod/..");
}
环绕通知
public void aroundMethod(ProceedingJoinPoint processdingJoinPoint) throws Throwable {
System.out.println("=====环绕");
processdingJoinPoint.proceed(); //调用目标方法
}
重点: 参数为ProceedingJoinPoint processdingJoinPoint
processdingJoinPoint.proceed()如果在环绕通知中不写,则目标方法不再执行
即环绕通知可以控制目标方法执行
写完各种通知,我们来看一下在配置文件中怎么配置aop和通知:
首先修改配置文件的文件头,加入ao依赖的xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
配置Bean:
<bean id = "personDao" class="com.my.spring.aop.xml.PersonImpl"></bean>
<!-- 切面(事务)-->
<bean id = "transcation" class="com.my.spring.aop.xml.Transcation"></bean>
然后开始配置aop:
利用<aop:config>
标签进行配置;
<aop:config>
<!--
切入点表达式 作用:确定目标类
-->
<aop:pointcut expression="execution(* com.my.spring.aop.xml.PersonImpl.*(..))"
id="perform"/>
<!-- ref指向的就是切面 -->
<aop:aspect ref="transcation">
<!-- 前置通知
1.在目标方法执行前执行
2.获取不到目标方法的返回值-->
<aop:before method="beginTranscation" pointcut-ref="perform"/>
<!-- 后置通知:
1.后置通知可以获取到目标方法的返回值
2.当目标方法抛出异常,后置通知将不再执行 -->
<aop:after-returning method="commit" pointcut-ref="perform" returning="val"/>
<!-- 最终通知
无论目标方法是否抛出异常,都将执行
-->
<aop:after method="finallyMethod" pointcut-ref="perform"/>
<!-- 异常通知
接收目标方法抛出的异常
-->
<aop:after-throwing method="thorwingMethod" throwing="ex" pointcut-ref="perform"/>
<!-- 环绕通知 (把前置,后置注释了)
控制目标方法的执行。processdingJoinPoint.proceed();
前置通知和后置通知能在目标方法的前面和后面加一些代码,但是不能控制目标方法的执行
-->
<aop:around method="aroundMethod" pointcut-ref="perform"/>
</aop:aspect>
</aop:config>
我们可能会对
<aop:pointcut expression="execution(* com.my.spring.aop.xml.PersonImpl.*(..))"
产生疑问,这的execution的代码是怎么写的呢?)这句话的主要目的是为了明确目标类,即我们的切面对那些类起作用,那么它的书写格式是什么呢?
下面我们举一些例子来看一下书写的规范:(引用一下其他老师的例子)
测试类:
public class TranscationText {
public void textTranscation() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonDao personDao = (PersonDao) applicationContext.getBean("personDao");
personDao.savePerson();
}
public static void main(String[] args) {
TranscationText text = new TranscationText();
text.textTranscation();
}
}
下面我们来说一下aop的执行原理:
1.当Spring容器启动时候,加载两个bean,对两个bean进行实例化。
2.当spring容器解析配置文件到<aop:config>
3.把切入点表达式解析出来,按照切入点表达式匹配sprin容器内部的bean
4.如果匹配成功,则为该bean创建代理对象。匹配不成功报错
5.当客户端getBean获取一个对象时,如果该对象有代理对象,则返回代理对象。
如果没有代理对象,返回代理对象本身。
为了更好理解aop,我们需要写更多的例子,来深入理解,毕竟aop是spring的核心,我还有好几个关于aop的例子,大家有兴趣可以评论留下你的邮箱。我会给你发需求和例子,在这就不多啰嗦了