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

  • 相关阅读:
    Linux Core Dump
    ODP.NET Managed正式推出
    获取EditText的光标位置
    (Java实现) 洛谷 P1603 斯诺登的密码
    (Java实现) 洛谷 P1603 斯诺登的密码
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1028 数的计算
  • 原文地址:https://www.cnblogs.com/yw0219/p/6004512.html
Copyright © 2011-2022 走看看