AOP:Aspect Oriented  Programming 面向切面编程

面向切面编程的核心是动态代理设计模式。请先參见动态代理设计模式笔记。

以Hibernate保存一个对象到数据库为例,因为保存数据时须要开启事务,利用面向切面编程思想,将事务的处理分离出来。当作一个切面来处理。

jdk的动态代理的缺点:

   1、在拦截器中,切入点的推断是很复杂的

   2、尽管实现了切面与目标类的松耦合,可是在拦截器中还得实现结合过程

一.springAOP的原理
目标类:在目标类的方法调用的前后,我们须要增加自己的逻辑。
切面:包括了全部的封装了自己的逻辑方法的类
切入点:目标类里的须要增加额外逻辑的方法。
通知:切面里的自己的封装自己的逻辑的方法;
比方Hibernate中,目标类是XDaoImpl,切入点是XDao.save(xx)方法,通知是开启事务,以及commit,切面就是封装了开启事务和commit的类;即在save方法运行前。须要開始事务,运行后,须要提交事务!


   1、当启动spring容器的时候,

         <bean id="classDao" class="cn.itheima03.spring.aop.xml.ClassesDaoImpl"></bean>

         <bean id="myTransaction" class="cn.itheima03.spring.aop.xml.MyTransaction"></bean>

把这两个bean创建对象了

   2、解析<aop:config>便签

        (1)、解析切入点表达式<aop:pointcut>。切入点针对的是函数,从函数进行切入,把表达式解除出来以后和              spring中的bean进行匹配

        (2)、假设匹配成功。则为该bean创建代理对象,在创建代理对象的过程中,把目标方法和通知结合在一起了

               假设匹配不成功。则直接报错

        (3)、当client调用context.getBean时,获取到的

                                          (1)、假设该对象有代理对象,则返回代理对象

                                          (2)、假设该对象没有代理对象。则返回对象本身

    3、<aop:aspect>切面标签:

          在切面中配置各种通知,这些通知就我们自己须要额外运行的逻辑。有的逻辑在切入点函数运行前运行,用<aop:before>配置。有的须要在切入点方法运行之后运行,使用<aop:after>配置。还有的是运行切入点函数出现异常后运行,等的。。

说明:

   spring容器内部会自己主动推断:

              假设目标类实现了接口。则採用jdkproxy

              假设目标类没有实现接口,则採用cglibproxy

二.关于通知(通知就是切面里的方法,又称Advive,是在方法运行前和后须要运行的自己的代码)
前置通知:

   1、在目标方法之前运行

   2、不管目标方法遇到异常都运行

后置通知:

   1、在目标方法之后运行

   2、假设目标方法遇到异常,则不运行

   3、能够获取连接点的一些信息

终于通知:

   1、相当于finally

   2、不管目标方法是否遇到异常,都运行



异常通知

   1、获取目标方法抛出的异常信息

   2、throwing參数的配置才干获取信息



围绕通知

   相当于jdkproxy的invoke方法

三.以下使用Spring的AOP来处理Hibernate保存对象。


1.配置文件:applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
      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" >
          
     <!-- 1、目标类 2、切面 3、进行AOP的配置 -->
     <bean id="classDao" class="cn.itheima03.spring.aop.xml.ClassesDaoImpl" ></bean>
     <bean id="myTransaction" class="cn.itheima03.spring.aop.xml.MyTransaction" ></bean>

     <aop:config >
           <!-- 切入点表达式 expression切入点表达式
id 唯一标示 -->
           <aop:pointcut
               expression="execution(*
cn.itheima03.spring.aop.xml.ClassesDaoImpl.*(..))"
               id= "perform" />

           <!-- ref 引向切面
切面里包括各种各样的通知,这些通知都是我们自己想要额外实现的东西,比方开启事务等。。-->

           <aop:aspect ref= "myTransaction">
               <!-- 方法运行之前运行
-->
               <aop:before method= "beginTransaction" pointcut-ref="perform" />

               <!-- 后置通知
returning 返回值  要与方法中的參数的名字相相应 -->
               <aop:after-returning method= "commit"   pointcut-ref="perform" returning="val" />

               <!-- 终于通知
不管目标方法是否有异常。都运行 -->
               <aop:after method= "finnalyMethod" pointcut-ref="perform" />

               <!-- 异常通知
throwing 获取目标方法抛出的异常信息 -->
               <aop:after-throwing method= "throwingMethod"  pointcut-ref="perform" throwing="ex" />

               <!-- 相当于
代理中invoke 方法,能够控制切入点的运行 -->
               <aop:around method= "aroundMethod" pointcut-ref="perform" />

           </aop:aspect>
     </aop:config >
</beans>

关于切入点表达式:切入点表达式匹配的是方法。一个方法的完整声明为:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
throws-pattern?)

问号代表可有可无,没有问号代表一定要有!

以下是一个方法完整声明的演示样例:
切入点表达式演示样例:
  • execution(public * *(..))  全部的公共方法
  • 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.itheima03.spring..*.*(String,*,Integer))
  • execution(* cn.itheima03.*.*.spring.*..*.*(..))  參数..代表随意类型的随意參数,參数能够是0个

如cn.itheima03.a.b.spring.c.d.A.a()能匹配最后一个表达式。



2.java代码:

public interface ClassesDao
{
     public void saveClasses(Classes
classes);
     
     public void updateClasses(Classes
classes);
     
     public List<Classes>
getClasses();
}
===========================================
public class ClassesDaoImpl extends HibernateUtils{

     public String
saveClasses(Classes classes) {
           int a =
1/0;
           sessionFactory.getCurrentSession().save(classes);
           return "aaaa" ;
     }

     public List<Classes>
getClasses() {
           return sessionFactory .getCurrentSession().createQuery("from
Classes").list();
     }

     public void updateClasses(Classes
classes) {
           sessionFactory.getCurrentSession().update(classes);
     }

}
===========================================
public class HibernateUtils
{
     public static SessionFactory sessionFactory;
     static{
          Configuration configuration = new Configuration();
          configuration.configure();
           sessionFactory =
configuration.buildSessionFactory();
     }
}
===========================================
public class MyTransaction extends HibernateUtils{
     private Transaction transaction;
     /**
      * 前置通知
      *    JoinPoint 可以调用该API得到连接点的一些信息
      */
     public void beginTransaction(JoinPoint
joinPoint){
          System. out.println(joinPoint.getSignature().getName());
           this.transaction = sessionFactory.getCurrentSession().beginTransaction();
     }
     
     /**
      * 后置通知
      *   1、获取目标方法的返回值
      */
     public void commit(Object
val){
          System. out.println(val);
           this.transaction .commit();
     }
     
     /**
      * 终于通知
      */
     public void finnalyMethod(){
          System. out.println("finally
method" );
     }
     
     /**
      * 异常通知
      */
     public void throwingMethod(Throwable
ex){
           /**
           * 输出目标方法的异常信息
           */
          System. out.println(ex.getMessage());
     }
     
     /**
      * 围绕通知
      *    1、假设不运行joinPoint.proceed();。目标方法是不运行的
      *    2、在目标方法运行的上下文加入内容
      */
     public void aroundMethod(ProceedingJoinPoint
joinPoint){
           try {
              System. out.println("aaaa" );
              joinPoint. proceed();//运行目标方法
              System. out.println("bbbb" );
          } catch (Throwable
e) {
              e.printStackTrace();
          }
     }
}
===========================================
/**
 * 注意的点
 *    1、代理对象的方法体的内容就是拦截器 中invoke方法体的内容
 *    2、在client,用代理对象调用方法的时候进去了invoke方法
 */
public class ClassesDaoTest
{
     @Test
     public void testSaveClasses(){
          ApplicationContext context = new ClassPathXmlApplicationContext("cn/itheima03/spring/aop/xml/applicationContext.xml" );
          ClassesDaoImpl classesDao = (ClassesDaoImpl)context.getBean("classDao" );
          Classes classes = new Classes();
          classes.setCname( "afds");
          classesDao.saveClasses(classes);
     }
}


四.多切面的样例


假如查看工资须要经过日志管理,安全管理,权限管理后才干查看工资。

目标类:查看工资的类
切面:日志管理,安全管理。权限管理
切入点:查看工资的方法

1.java代码:
/**
 * 切面
 * 日志管理
 */
public class Logger
{
     public void interceptor()
{
          System. out.println("logging" );
     }
}
===========================================
/**
 * 安全管理
 */
public class Security
{
     public void interceptor()
{
          System. out.println("security" );
     }
}
===========================================
/**
 * 权限管理
 */
public class Privilege{
     
     private String access;

     public String
getAccess() {
           return access ;
     }

     public void setAccess(String
access) {
           this.access =
access;
     }

     public void interceptor(ProceedingJoinPoint
joinPoint) {
           if("admin" .equals(this.access)){
               try {
                   joinPoint.proceed();
              } catch (Throwable
e) {
                   e.printStackTrace();
              }
          } else{
              System. out.println("对不起,没有权限查看...." );
          }
     }
}
===========================================
/**
 * 目标类
 */
public class SalaryManagerImpl implements SalaryManager{

     @Override
     public void showSalary()
{
          System. out.println("正在查看工资" );
     }
     
}
===========================================
public class SalaryTest
{
     @Test
     public void test(){
          ApplicationContext context= new ClassPathXmlApplicationContext("cn/itheima03/spring/aop/multiaspect/applicationContext.xml" );
          SalaryManager salarmManager=(SalaryManager) context.getBean("salaryManager" );
          salarmManager.showSalary();
     }
}
===========================================

2.配置文件:
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:aop="http://www.springframework.org/schema/aop"
      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" >

     <!--目标类, 切面类,aop 
-->

     <bean id="salaryManager" class="cn.itheima03.spring.aop.multiaspect.SalaryManagerImpl" ></bean>
     
     <bean id="logger" class="cn.itheima03.spring.aop.multiaspect.Logger" ></bean>
     <bean id="security" class="cn.itheima03.spring.aop.multiaspect.Security" ></bean>
     <bean id="privilege" class="cn.itheima03.spring.aop.multiaspect.Privilege" >
           <property name= "access" value="admin" ></property>
     </bean >
     
     <aop:config >
           <!--切入点  -->
           <aop:pointcut expression="execution(*
cn.itheima03.spring.aop.multiaspect.SalaryManagerImpl.*(..))"
 id ="sm"/>
           <!-- 切面 -->
           <aop:aspect ref= "logger">
               <aop:before method= "interceptor" pointcut-ref="sm" />
           </aop:aspect>
          
           <aop:aspect ref= "security">
               <aop:before method= "interceptor" pointcut-ref="sm" />
           </aop:aspect>
          
           <aop:aspect ref= "privilege">
               <!--围绕切入点 
-->
               <aop:around method= "interceptor" pointcut-ref="sm" />
           </aop:aspect>
     </aop:config >
</beans>


最新文章

  1. 文件缓存(配合JSON数组)
  2. PHP 数据库连接工具类(MySQLI函数包装)
  3. 原生js实现查询天气的小应用
  4. Nginx学习笔记(三) Nginx基本数据结构
  5. 金融系列5《AUTH过程》
  6. sgu - 274 - Spam-filter
  7. WF编译报错
  8. java中解决request中文乱码问题
  9. vld(Visual Leak Detector) 内存泄露检测工具
  10. ZooKeeper监听机制
  11. 201521123060 《Java程序设计》第8周学习总结
  12. Nginx服务器配置之location语法分析
  13. JavaScript定义函数
  14. Unique Morse Code Words
  15. colgroup和col的区别
  16. spring boot(十一)MongoDB的使用
  17. HDU 1003 MAXSUM(最大子序列和)
  18. nginx 跳转系列
  19. [转载]DOMContentLoaded与interactive
  20. 基于Window10搭建android开发环境

热门文章

  1. kill 8080 port on windows
  2. CF897C Nephren gives a riddle
  3. android调用webservice接口获取信息
  4. jboss 配置虚拟路径
  5. 梦想CAD控件 2018.7.26更新
  6. day02python
  7. 04Servlet的生命周期
  8. du 命令计算隐藏文件夹或文件
  9. Linux---shell基本指令
  10. springboot+idea+jsp 404问题