博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Spring四】AOP之XML配置
阅读量:6537 次
发布时间:2019-06-24

本文共 8502 字,大约阅读时间需要 28 分钟。

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
>

转载于:https://www.cnblogs.com/gavanwanggw/p/6859674.html

你可能感兴趣的文章
Google插件switchysharp的用法
查看>>
中国最强的人工智能学术会议来了
查看>>
Metasploit的射频收发器功能 | Metasploit’s RF Transceiver Capabilities
查看>>
主库 归档 删除策略
查看>>
Chrome 更新策略大变:优先安装 64 位版本
查看>>
《Linux从入门到精通(第2版)》——导读
查看>>
路过下载攻击利用旧版 Android 漏洞安装勒索软件
查看>>
ThinkSNS 六大子版本体验及源码下载
查看>>
《算法基础》——1.5实际因素
查看>>
《Java数字图像处理:编程技巧与应用实践》——第3章 基本Swing UI组件与图像显示 3.1 JPanel组件与BufferedImage对象的显示...
查看>>
为什么有人讨厌 Google 的新 Logo?
查看>>
2022 年 AI 会发展成什么样子,IBM 做出了 5 大预测
查看>>
腾讯2017暑期实习编程题3
查看>>
Intellij IDEA 构建Spring Web项目 — 用户登录功能
查看>>
[AHOI2013]作业
查看>>
git push被忽略的文件 处理
查看>>
C#中用ILMerge将所有引用的DLL打成一个DLL文件
查看>>
PHP生成HTML静态页面
查看>>
Makefile 中:= ?= += =的区别【转】
查看>>
使用makecontext实现用户线程【转】
查看>>