zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    https下 http的会被阻塞 This request has been blocked; the content must be served over HTTPS.
    一文揭秘定时任务调度框架quartz
    JAVA开发者的Golang快速指南
    postman传递对象到spring controller的方式
    Go语言程序结构分析初探
    avalon1.3的新特性预览
    html标签对应的英文原文
    迷你MVVM框架 avalonjs 实现上的几个难点
    firebug,chrome调试工具的使用
    迷你MVVM框架 avalonjs 1.2.4发布
  • 原文地址:https://www.cnblogs.com/friends-wf/p/3784466.html
Copyright © 2011-2022 走看看