首页 > 代码库 > spring中的AOP 以及各种通知

spring中的AOP 以及各种通知

理解了前面动态代理对象的原理之后,其实还是有很多不足之处,因为如果在项目中有20多个类,每个类有100多个方法都需要判断是不是要开事务,那么方法调用那里会相当麻烦。

spring中的AOP很好地解决了这个问题,通过 execution表达式 指定哪些包中的那些类 哪些方法 用到事务

executionpublic * *..))  所有的公共方法

execution(* set*..))  以set开头的任意方法

execution(* com.xyz.service.AccountService.*..)) com.xyz.service.AccountService类中的所有的方法

execution(* com.xyz.service.*.*..))  com.xyz.service包中的所有的类的所有的方法

execution(* com.xyz.service..*.*..)) com.xyz.service包及子包中所有的类的所有的方法

execution(* cn.itcast.spring.sh..*.*(String,?,Integer))  cn.itcast.spring.sh包及子包中所有的类的有三个参数

                                                            第一个参数为String,第二个参数为任意类型,

                                                            第三个参数为Integer类型的方法

 

 

springAOP的具体加载步骤:

   1、当spring容器启动的时候,加载了spring的配置文件

   2、为配置文件中所有的bean创建对象

   3、spring容器会解析aop:config的配置

       1、解析切入点表达式,用切入点表达式和纳入spring容器中的bean做匹配

            如果匹配成功,则会为该bean创建代理对象,代理对象的方法=目标方法+通知

            如果匹配不成功,不会创建代理对象

   4、在客户端利用context.getBean获取对象时,如果该对象有代理对象则返回代理对象,如果代理对象,则返回目标对象

说明:如果目标类没有实现接口,则spring容器会采用cglib的方式产生代理对象,如果实现了接口,会采用jdk的方式

 

实例:

引入包

aspectjrt.jar

aspectjweaver.jar

Person.java

 1 package cn.itcast.sh.aop;
 2 
 3 
 4 import java.io.Serializable;
 5 
 6 
 7 /**
 8  * 对象的序列化的作用:让对象在网络上传输,以二进制的形式传输
 9  * @author Think
10  * Serializable标示接口
11  */
12 public class Person implements Serializable{
13     private Long pid;
14     private String pname;
15     
16     public Person(){}
17     
18     public Person(String pname){
19         this.pname = pname;
20     }
21     
22     public Long getPid() {
23         return pid;
24     }
25     public void setPid(Long pid) {
26         this.pid = pid;
27     }
28     public String getPname() {
29         return pname;
30     }
31     public void setPname(String pname) {
32         this.pname = pname;
33     }
34     public String getPsex() {
35         return psex;
36     }
37     public void setPsex(String psex) {
38         this.psex = psex;
39     }
40     private String psex;
41 }
View Code

PersonDao.java

1 package cn.itcast.sh.aop;
2 
3 public interface PersonDao {
4     public void savePerson(Person person);
5 }
View Code

PersonDaoImpl.java

 1 package cn.itcast.sh.aop;
 2 
 3 import org.hibernate.Session;
 4 
 5 import cn.itcast.hibernate.sh.utils.HiberanteUtils;
 6 
 7 public class PersonDaoImpl extends HiberanteUtils implements PersonDao{
 8 
 9     @Override
10     public void savePerson(Person person) {
11         Session session=sessionFactory.getCurrentSession();
12         session.save(person);
13     }
14 
15 }
View Code

定义切面 MyTransaction.java

 1 package cn.itcast.sh.aop;
 2 
 3 import org.hibernate.Transaction;
 4 
 5 import cn.itcast.hibernate.sh.utils.HiberanteUtils;
 6 
 7 public class MyTransaction extends HiberanteUtils{
 8 
 9     private Transaction tran;
10     public void beginTransaction()
11     {
12         tran=sessionFactory.getCurrentSession().beginTransaction();
13     }
14     public void commit()
15     {
16         tran.commit();
17     }
18 }
View Code

hibernate.cfg.xml

 1 <?xml version=‘1.0‘ encoding=‘utf-8‘?>
 2 <!DOCTYPE hibernate-configuration PUBLIC
 3         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 4         "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
 5 <hibernate-configuration>
 6     <!-- 
 7         一个session-factory只能连接一个数据库
 8     -->
 9 <session-factory>
10     <!-- 
11         数据库的用户名
12     -->
13     <property name="connection.username">root</property>
14 
15     <property name="connection.driver_class">
16         com.mysql.jdbc.Driver
17     </property>
18 
19     <!-- 
20         密码
21     -->
22     <property name="connection.password">friends</property>
23     <!-- 
24         url
25     -->
26     <property name="connection.url">
27         jdbc:mysql://localhost:3306/hibernate_basic
28     </property>
29     <!-- 
30         作用:根据持久化类和映射文件生成表
31         validate
32         create-drop
33         create
34         update
35     -->
36     <property name="hbm2ddl.auto">update</property>
37 
38     <property name="hibernate.dialect">
39         org.hibernate.dialect.MySQLInnoDBDialect
40     </property>
41 <!--     用于配置当前线程用的 -->
42     <property name="current_session_context_class">thread</property>
43     <!-- 
44         显示hibernate内部生成的sql语句
45     -->
46     <property name="show_sql">true</property>
47     <property name="format_sql">true</property>
48     <mapping resource="cn/itcast/sh/aop/Person.hbm.xml" />
49 
50 </session-factory>
51 </hibernate-configuration>
View Code

重点applicationContext-aop.xml配置spring提供的切面

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:aop="http://www.springframework.org/schema/aop" 
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xsi:schemaLocation="http://www.springframework.org/schema/beans
 6            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 7            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 8     <!-- 
 9         导入目标类,导入切面
10      -->       
11      <bean id="personDao" class="cn.itcast.sh.aop.PersonDaoImpl"></bean>
12      
13      <bean id="myTransaction" class="cn.itcast.sh.aop.MyTransaction"></bean>
14      
15      <!-- 
16          aop的配置
17       -->
18       <aop:config>
19           <!-- 
20                切入点表达式
21            -->
22           <aop:pointcut expression="execution(* cn.itcast.sh.aop.PersonDaoImpl.*(..))" id="perform"/>
23           <aop:aspect ref="myTransaction">
24           
25               <aop:before method="beginTransaction" pointcut-ref="perform"/>
26               <aop:after-returning method="commit" pointcut-ref="perform"/> 
27 
28 <!--               <aop:after method="finallyMethod" pointcut-ref="perform"/> -->
29 <!--               <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/> -->
30 <!--               <aop:around method="aroundMethod" pointcut-ref="perform"/> -->
31           </aop:aspect>
32       </aop:config>
33 </beans>

测试类 

 1 package cn.itcast.sh.aop;
 2 
 3 import org.junit.Test;
 4 import org.springframework.context.ApplicationContext;
 5 import org.springframework.context.support.ClassPathXmlApplicationContext;
 6 
 7 public class test {
 8     @Test
 9     public void testAop()
10     {
11         Person p=new Person();
12         p.setPname("new comer");
13         p.setPsex("boy");
14         
15         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-aop.xml");
16         PersonDao dao=(PersonDao) context.getBean("personDao");
17         dao.savePerson(p);
18     }
19     
20 }

 

示例二: 返回值通过 applicationContext.xml中在通知后面添加参数来配置返回值

例如后置通知中 配置 returinn属性

通知:

   1、前置通知

      1、在目标方法执行之前执行

      2、无论目标方法是否抛出异常,都执行,因为在执行前置通知的时候,目标方法还没有执行,还没有遇到异常

   2、后置通知

      1、在目标方法执行之后执行

      2、当目标方法遇到异常,后置通知将不再执行

      3、后置通知可以接受目标方法的返回值,但是必须注意:aop:after-returning标签

               后置通知的参数的名称和配置文件中returning="var"的值是一致的

   3、最终通知:

      1、在目标方法执行之后执行

      2、无论目标方法是否抛出异常,都执行,因为相当于finally

   4、异常通知

      1、接受目标方法抛出的异常信息

      2、步骤

           在异常通知方法中有一个参数Throwable  ex

           在配置文件中

              <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/>

   5、环绕通知             用于判断条件是否让目标方法执行

       1、如果不在环绕通知中调用ProceedingJoinPoint的proceed,目标方法不会执行

       2、环绕通知可以控制目标方法的执行

 

PersonDaoImpl.java

 1 package cn.itcast.spring.aop.sh;
 2 
 3 import java.lang.reflect.Method;
 4 
 5 import org.junit.Test;
 6 
 7 import cn.itcast.spring.aop.annotation.sh.HibernateUtils;
 8 import cn.itcast.spring.aop.annotation.sh.Person;
 9 
10 public class PersonDaoImpl extends HibernateUtils{
11     public String savePerson(Person person) {
12         // TODO Auto-generated method stub
13         //int a = 1/0;
14         //sessionFactory.getCurrentSession().save(person);
15         System.out.println("aaaa");
16         return "aaaa";
17     }
18 }

 

用到的类和方法和上面相同,只不过改切面的文件(MyTransaction.java)和 applicationContext-aop.xml文件

 1 package cn.itcast.spring.aop.sh;
 2 
 3 import org.aspectj.lang.JoinPoint;
 4 import org.aspectj.lang.ProceedingJoinPoint;
 5 import org.hibernate.Transaction;
 6 
 7 import cn.itcast.spring.aop.annotation.sh.HibernateUtils;
 8 
 9 public class MyTransaction extends HibernateUtils{
10     private Transaction transaction;
11     /**
12      * 通过该参数可以获取目标方法的一些信息        
13      *在每个通知中都可以加入 JoinPoint joinpoint参数
14      * @param joinpoint
15      */
16     public void beginTransaction(JoinPoint joinpoint){
17         System.out.println("bbb");
18         this.transaction = sessionFactory.getCurrentSession().beginTransaction();
19     }
20                             //var是目标方法的返回值,以上的savePerson函数返回值 aaaa
21     public void commit(Object var){         //保持与 application-aop.xml 中的aop:after-returning元素中 returning中的属性值一致
22         System.out.println(var);
23         this.transaction.commit();
24     }
25     
26     public void finallyMethod(){
27         System.out.println("finally method");
28     }
29     
30     /**
31      * 异常通知
32      * @param ex
33      */
34     public void throwingMethod(Throwable ex){    //保持与 application-aop.xml 中的aop:after-returning元素中 throwing中的属性值一致
35         System.out.println(ex.getMessage());
36     }
37       //JoinPoint是 ProceedingJoinPoint的父类 
38 public void aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{ 
39        System.out.println(joinPoint.getSignature().getName()); 
40        joinPoint.proceed();//调用目标方法 
41        System.out.println("aaaasfdasfd"); 
42     } 
43  }

 applicationContext-aop.xm

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:aop="http://www.springframework.org/schema/aop" 
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xsi:schemaLocation="http://www.springframework.org/schema/beans
 6            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 7            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 8     <!-- 
 9         导入目标类,导入切面
10      -->       
11      <bean id="personDao" class="cn.itcast.spring.aop.sh.PersonDaoImpl"></bean>
12      
13      <bean id="myTransaction" class="cn.itcast.spring.aop.sh.MyTransaction"></bean>
14      
15      <!-- 
16          aop的配置
17       -->
18       <aop:config>
19           <!-- 
20                切入点表达式
21            -->
22           <aop:pointcut expression="execution(* cn.itcast.spring.aop.sh.PersonDaoImpl.*(..))" id="perform"/>
23           <aop:aspect ref="myTransaction">
24           <!-- 
25         前置通知 <aop:before method="beginTransaction" pointcut-ref="perform"/>
26        后置通知 <aop:after-returning method="commit" pointcut-ref="perform" returning="var"/>
27            --><!--最终通知   异常通知   环绕通知 用于判断是否执行目标对象的-->
28               <aop:after method="finallyMethod" pointcut-ref="perform"/>
29               <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/>
30               <aop:around method="aroundMethod" pointcut-ref="perform"/>
31           </aop:aspect>
32       </aop:config>
33 </beans>

 测试

 1 package cn.itcast.spring.aop.sh;
 2 
 3 import org.junit.Test;
 4 import org.springframework.context.ApplicationContext;
 5 import org.springframework.context.support.ClassPathXmlApplicationContext;
 6 
 7 import cn.itcast.spring.aop.annotation.sh.Person;
 8 import cn.itcast.spring.aop.annotation.sh.PersonDaoImpl;
 9 
10 public class PersonTest {
11     @Test
12     public void test(){
13         ApplicationContext context = new ClassPathXmlApplicationContext("cn/itcast/spring/aop/sh/applicationContext.xml");
14         PersonDaoImpl personDao = (PersonDaoImpl)context.getBean("personDao");
15         Person person = new Person();
16         person.setPname("aaas");
17         personDao.savePerson(person);
18     }
19 }
View Code