zoukankan      html  css  js  c++  java
  • Spring-AOP

    记得上小学时候,上课前班长或者学习委员都会带头喊:起立,然后童鞋们起立齐喊:老师好才开始上课,下课同样起立喊老师再见,整节课才算完成。其实这是一种仪式,并不是某一位老师特别教授的技能,但又必须做,而且无论什么课程都需要举行,这种就类似于程序中的非核心业务,不能与核心业务混为一体,只是在需要出现的地方出现,为处理这种矛盾,从而就有了专门处理的方法或理念,叫面向切面编程AOP,Spring支持AOP,下面就以学生上课为例进行示范:


    JavaConfig:

     1 package com.spring.config;
     2 
     3 import org.springframework.context.annotation.ComponentScan;
     4 import org.springframework.context.annotation.Configuration;
     5 import org.springframework.context.annotation.EnableAspectJAutoProxy;
     6 
     7 @Configuration
     8 @ComponentScan(basePackages={"com.spring"})
     9 @EnableAspectJAutoProxy
    10 public class CreatureSpingConfig {
    11 }
    配置类
     1 package com.spring.aop;
     2 
     3 import org.aspectj.lang.ProceedingJoinPoint;
     4 import org.aspectj.lang.annotation.After;
     5 import org.aspectj.lang.annotation.Around;
     6 import org.aspectj.lang.annotation.Aspect;
     7 import org.aspectj.lang.annotation.Before;
     8 import org.aspectj.lang.annotation.Pointcut;
     9 import org.springframework.stereotype.Component;
    10 
    11 @Component
    12 @Aspect//需要引入aspectjrt-1.*.*.jar,此处版本需要和jdk版本匹配
    13 public class Sophomore implements Student{
    14 /**
    15 * 定义切点,下面的没有方法体的方法只是相当于一个别名
    16 */
    17 @Pointcut("execution(* com.spring.aop.ChineseTeacher.teach(..))")
    18 public void begin(){}
    19 @Pointcut("execution(* com.spring.aop.ChineseTeacher.classOver(..))")
    20 public void over(){}
    21 
    22 @Before("begin()")
    23 public void beforeTest(){
    24 System.out.println("班长:上课!
    童鞋们:老师好!");
    25 }
    26 @Around("begin()")
    27 public void aroundTest(ProceedingJoinPoint p){
    28 try {
    29 System.out.println("叮铃铃~");
    30 p.proceed();//继续执行连接点的方法,如果不写表示不调用这个连接点的方法
    31 } catch (Throwable e) {
    32 System.out.println("自习ing");//上课出错则自习
    33 }
    34 }
    35 @Before("over()")
    36 public void ringTest(){
    37 System.out.println("叮铃铃~");
    38 }
    39 @After("over()")
    40 public void afterTest(){
    41 System.out.println("班长:下课!
    童鞋们:老师再见!");
    42 }
    43 }
    学生实现类
     1 package com.spring.aop;
     2 
     3 import org.springframework.stereotype.Component;
     4 
     5 @Component
     6 public class ChineseTeacher implements Teacher{
     7     @Override
     8     public void teach() {
     9         System.out.println("同学们好,今天我们来学习一首诗《锄禾》...");
    10     }
    11     public void classOver(){
    12         System.out.println("今天先讲到这里,同学们下课!");
    13     }
    14 }
    教师实现类
     1 package com.spring.test;
     2 
     3 import org.junit.Test;
     4 import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
     5 import org.junit.runner.RunWith;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.test.context.ContextConfiguration;
     8 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
     9 
    10 import com.spring.aop.Teacher;
    11 @RunWith(SpringJUnit4ClassRunner.class)
    12 @ContextConfiguration(classes=com.spring.config.CreatureSpingConfig.class)
    13 public class SpringJunit {
    14 public static StandardOutputStreamLog log=new StandardOutputStreamLog();
    15 @Autowired
    16 private Teacher t;
    17     @Test
    18     public void notNull() {
    19         t.teach();
    20         System.out.println("45分钟后...");
    21         t.classOver();
    22     }
    23 }
    测试类

    XML:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans
     3     xmlns="http://www.springframework.org/schema/beans"
     4     xmlns:c="http://www.springframework.org/schema/c"
     5     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     6     xmlns:p="http://www.springframework.org/schema/p"
     7     xmlns:jdbc="http://www.springframework.org/schema/jdbc"
     8     xmlns:jee="http://www.springframework.org/schema/jee"
     9     xmlns:aop="http://www.springframework.org/schema/aop"
    10     xmlns:context="http://www.springframework.org/schema/context"
    11     xmlns:conditional="http://www.springframework.org/schema/context"
    12     xsi:schemaLocation="http://www.springframework.org/schema/beans 
    13     http://www.springframework.org/schema/beans/spring-beans.xsd
    14     http://www.springframework.org/schema/context 
    15     http://www.springframework.org/schema/context/spring-context.xsd
    16     http://www.springframework.org/schema/jdbc 
    17     http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
    18     http://www.springframework.org/schema/aop
    19     http://www.springframework.org/schema/aop/spring-aop.xsd
    20     http://www.springframework.org/schema/jee 
    21     http://www.springframework.org/schema/jee/spring-jee.xsd
    22     http://www.springframework.org/schema/conditional 
    23     http://www.springframework.org/schema/conditional/spring-conditional.xsd">
    24     <context:annotation-config ></context:annotation-config>
    25     <bean id="chineseTeacher" class="com.spring.aop.ChineseTeacher"></bean>
    26     <bean id="sophomore" class="com.spring.aop.Sophomore"></bean>
    27     <aop:aspectj-autoproxy proxy-target-class="true"/>
    28     <aop:config>
    29         <aop:aspect ref="sophomore">
    30             <aop:pointcut expression="execution(* com.spring.aop.ChineseTeacher.teach(..))" id="begin()"/>
    31             <aop:pointcut expression="execution(* com.spring.aop.ChineseTeacher.classOver(..))" id="over()"/>
    32             <aop:around method="aroundTest" pointcut-ref="begin()"/>
    33             <aop:before method="beforeTest()" pointcut-ref="begin()"/>
    34             <aop:before method="ringTest()" pointcut-ref="over()"/>
    35             <aop:after method="afterTest()" pointcut-ref="over()"/>
    36         </aop:aspect>
    37     </aop:config>
    38 </beans>
    XML

    配置类:

     1 package com.spring.config;
     2 
     3 import org.springframework.context.annotation.ComponentScan;
     4 import org.springframework.context.annotation.Configuration;
     5 import org.springframework.context.annotation.EnableAspectJAutoProxy;
     6 
     7 @Configuration
     8 @ComponentScan(basePackages={"com.spring"})
     9 @EnableAspectJAutoProxy
    10 public class SpringConfig {
    11 }
    配置类

    学生实现类:

     1 package com.spring.aop;
     2 
     3 import org.aspectj.lang.ProceedingJoinPoint;
     4 import org.aspectj.lang.annotation.After;
     5 import org.aspectj.lang.annotation.Around;
     6 import org.aspectj.lang.annotation.Aspect;
     7 import org.aspectj.lang.annotation.Before;
     8 import org.aspectj.lang.annotation.Pointcut;
     9 import org.springframework.stereotype.Component;
    10 public class Sophomore implements Student{
    11 public void beforeTest(){
    12 System.out.println("班长:上课!
    童鞋们:老师好!");
    13 }
    14 public void aroundTest(ProceedingJoinPoint p){
    15 try {
    16 System.out.println("叮铃铃~");
    17 p.proceed();//继续执行连接点的方法,如果不写表示不调用这个连接点的方法
    18 } catch (Throwable e) {
    19 System.out.println("自习ing");//上课出错则自习
    20 }
    21 }
    22 public void ringTest(){
    23 System.out.println("叮铃铃~");
    24 }
    25 public void afterTest(){
    26 System.out.println("班长:下课!
    童鞋们:老师再见!");
    27 }
    28 }
    学生实现类

    教师实现类:

     1 package com.spring.aop;
     2 
     3 public class ChineseTeacher implements Teacher{
     4     public void teach() {
     5         System.out.println("同学们好,今天我们来学习一首诗《锄禾》...");
     6     }
     7     public void classOver(){
     8         System.out.println("今天先讲到这里,同学们下课!");
     9     }
    10 }
    教师实现类

    测试:

     1 package com.spring.aop;
     2 
     3 import org.junit.Test;
     4 import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
     5 import org.junit.runner.RunWith;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.test.context.ContextConfiguration;
     8 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
     9 
    10 import com.spring.aop.Teacher;
    11 @RunWith(SpringJUnit4ClassRunner.class)
    12 @ContextConfiguration(locations="/spring.xml")
    13 public class SpringJunit {
    14 public static StandardOutputStreamLog log=new StandardOutputStreamLog();
    15 @Autowired
    16 private Teacher t;
    17     @Test
    18     public void notNull() {
    19         t.teach();
    20         System.out.println("45分钟后...");
    21         t.classOver();
    22     }
    23 }
    测试类

    结果:

     总结:

    1. @Aspect需要导入aspectjrt.jar;
    2. 在配置类或xml配置文件中应配置@EnableAspectJAutoProxy或<aop:aspectj-autoproxy/>
    3. 需要引入aopaliance.jar,否则会报错:java.lang.ClassNotFoundException: org.aopalliance.intercept.MethodInterceptor
    4. 需要引入aspectjweaver.jar,否则会报错:java.lang.ClassNotFoundException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException
    5. 过程中可能出现如下异常:java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut teach,原因是:aspectjrt.jar版本与jdk版本不一致,解决办法参考:http://www.cnblogs.com/xing901022/p/4267563.html
    6. jar包下载地址:http://mavenrepository.com/
    7. JavaConfig方式中:before方法的优先级比around低
    8. execution(* com.spring.aop.ChineseTeacher.teach(..))扩展

      AOP支持的AspectJ切入点指示符如下:

               execution用于匹配方法执行的连接点;

               within用于匹配指定类型内的方法执行;

               this用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;

               target用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;

               args用于匹配当前执行的方法传入的参数为指定类型的执行方法;

               @within用于匹配所以持有指定注解类型内的方法

               @target用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;

               @args用于匹配当前执行的方法传入的参数持有指定注解的执行;

               @annotation用于匹配当前执行方法持有指定注解的方法;

               beanSpring AOP扩展的,AspectJ没有对于指示符,用于匹配特定名称的Bean对象的执行方法;

               reference pointcut表示引用其他命名切入点,只有@ApectJ风格支持,Schema风格不支持。

             AspectJ切入点支持的切入点指示符还有: call、get、set、preinitialization、staticinitialization、initialization、handler、adviceexecution、withincode、cflow、cflowbelow、if、@this、@withincode;但Spring AOP目前不支持这些指示符,使用这些指示符将抛出IllegalArgumentException异常。这些指示符Spring AOP可能会在以后进行扩展。

    9. XML方式中,执行顺序是自上而下,与JavaConfig方式不同;
    10. XML方式中,在<aop:around>标签中,method方法不需加(),无参方法可以,如果是around方法,必须有ProceedingJoinPoint类的参数,因此会报错:

      Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#1d03f44': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: Unable to locate method [aroundTest()] on bean [sophomore]
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
      at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:276)
      ... 65 more

  • 相关阅读:
    应用图标大小
    AndroidStudio使用笔记
    shell 三剑客之 sed 命令详解
    shell 三剑客之 sed pattern 详解
    shell 文本处理三剑客之 grep 和 egrep
    Shell 编程中的常用工具
    shell 函数的高级用法
    shell 数学运算
    shell 变量的高级用法
    nginx 之 https 证书配置
  • 原文地址:https://www.cnblogs.com/yw0219/p/6004512.html
Copyright © 2011-2022 走看看