SpringAOP的几种配置

来源:互联网 发布:java用sleep内存泄露 编辑:程序博客网 时间:2024/06/05 03:57

Spring实现AOP其实本质是有两种方式.
- 1 基于XML配置的方式,
基于XML的方式又细分为两种
- 基于代理实现的AOP
- 纯pojo切面,基于SpringAop容器实现的
- 2 基于注解的方式
现在就来说基于XML形式的第一种:基于代理模式的实现.
如果说我们要实现aop通知的那个类实现的有其他接口的话,那么使用的代理模式就是JDK自带的动态代理模式,无实现接口的话是用CGIB动态代理模式.
   这里使用有实现接口的业务类.上代码,
- (1)可睡觉的接口,任何可以睡觉的人或机器都可以实现它

public interface Sleepable {      public void sleep();  }  
  • (2)接口实现类,“Me”可以睡觉,“Me”就实现可以睡觉的接口。
public class Me implements Sleepable{      public void sleep() {          System.out.println("\n睡觉!不休息哪里有力气学习!\n");      }  }  
  • (3)Me关注于睡觉的逻辑,但是睡觉需要其他功能辅助,比如睡前脱衣服,起床脱衣服,这里开始就需要AOP替“Me”完成!解耦!首先需要一个SleepHelper(切面类)类。因为一个是切入点前执行、一个是切入点之后执行,所以实现对应接口(这是与另外一种XML方式区别的地方,纯pojo,Spring容器实现的方法,切面类没有实现这些接口)
public class SleepHelper implements MethodBeforeAdvice, AfterReturningAdvice {      public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {          System.out.println("睡觉前要脱衣服!");      }      public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {          System.out.println("起床后要穿衣服!");      }  }  
  • (4)Spring核心配置文件application.xml配置AOP。
<!-- 定义被代理者 -->     <bean id="me" class="com.springAOP.bean.Me"></bean>     <!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->     <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>     <!-- 定义切入点位置 -->     <bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">          <property name="pattern" value=".*sleep"></property>     </bean>     <!-- 使切入点与通知相关联,完成切面配置 -->     <bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">          <property name="advice" ref="sleepHelper"></property>                 <property name="pointcut" ref="sleepPointcut"></property>     </bean>     <!-- 设置代理 -->     <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">          <!-- 代理的对象,有睡觉能力 -->          <property name="target" ref="me"></property>          <!-- 使用切面 -->          <property name="interceptorNames" value="sleepHelperAdvisor"></property>          <!-- 代理接口,睡觉接口 -->          <property name="proxyInterfaces" value="com.springAOP.bean.Sleepable"></property>      </bean>  </beans>  

image

现在就来说基于XML形式的第二种:
- (1)修改后的SleepHelper类,很正常的类,所以这种方式的优点就是在代码中不体现任何AOP相关配置,纯粹使用xml配置。

public class SleepHelper{      public void beforeSleep(){          System.out.println("睡觉前要脱衣服!");      }      public void afterSleep(){          System.out.println("睡醒了要穿衣服!");      }  }  
  • (2) 业务类不做修改
  • (3)配置文件:
<!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->      <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>      <!-- 定义被代理者 -->      <bean id="me" class="com.springAOP.bean.Me"></bean>      <aop:config>          <aop:aspect ref="sleepHelper">              <aop:before method="beforeSleep" pointcut="execution(* *.sleep(..))" />              <aop:after method="afterSleep" pointcut="execution(* *.sleep(..))" />          </aop:aspect>      </aop:config>  </beans>  
  • (4)测试 ,结果一致.

基于注解实现的方式
这种方式简单,代码简洁.
- (1)同样的例子,修改后的SleepHelper:

/**     * @Aspect     * 定义这个类为切面类     */@Aspect  public class SleepHelper{      public SleepHelper(){      }        /**     * @Pointcut("execution(* *.sleep())")     * 定义这个方法为切入点,括号里面是execution()表达式     * 表示切入到的位置为-->返回值为任何形式,任何包的任何类的sleep()方法上.     * 注意是无参的     *      */    @Pointcut("execution(* *.sleep())")      public void sleeppoint(){}        /**     * @Before("sleeppoint()")     * 定义这个方法作为前置通知.     * 并在sleeppoint()所指定的切点上执行这个前置通知     */    @Before("sleeppoint()")      public void beforeSleep(){          System.out.println("睡觉前要脱衣服!");      }      @AfterReturning("sleeppoint()")      public void afterSleep(){          System.out.println("睡醒了要穿衣服!");      }  }  
  • (3)然后修改配置为:
<!-- 开启支持@AspectJ风格的切面声明 --> <aop:aspectj-autoproxy />  <!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->  <bean id="sleepHelper" class="com.springAOP.bean.SleepHelper"></bean>  <!-- 定义被代理者 -->  <bean id="me" class="com.springAOP.bean.Me"></bean>  
  • (4)最后测试,一样的结果!

PS:
@Component注解


如果切面类上除了@Aspect注解外还加上一个@Component注解,那么XML配置就不用写

<bean id="" class=""> </bean>

之类的bean组件.但是XML需要加入扫描注解的配置:

<context:component-scan base-package="com.qiushiju">        <!-- 扫描包括这些路径下的类 -->        <context:include-filter type="annotation" expression=""/>        <!-- 告诉主容器不要扫描加有@Controller 这些类,这些bean 是由web容器进行管理的 -->        <context:exclude-filter type="annotation"            expression="org.springframework.stereotype.Controller" />    </context:component-scan>


因为@Component注解就是声明这个类是Spring容器托管的类,会扫描到自动加载的.与@Controller @Service @Repository功能一样.

@Pointcut(@annotation)注解

@Pointcut(@annotation)与 @Pointcut(“execution(* .(..)”)的区别
@Pointcut(“execution(* .(..)”)是在指定的返回参数类型,指定路径的指定方法上切入进行各种通知操作,如上面的代码.
@Pointcut(@annotation)是适用于自定义注解的情况.我自定义一个一个注解类

@Target({ElementType.METHOD})      @Retention(RetentionPolicy.RUNTIME)      public @interface MyLog {  /** * 日志描述 */  String desc()  default "";   /** * 操作表类型 */  int type() default "";  }

如果要在这个注解所在的方法(一般是Controller层的方法上)使用AOP的通知操作(一般做日志处理),那就把这个注解类定义为切点.即在切面类中定义切点的时候使用@Pointcut(@annotation)方式声明

@Pointcut("@annotation(com.qiushiju.demo.common.annotion.log.MyLog)")    public void cutService() {    }

     这样在调用加了@MyLog注解的controller层方法时,@MyLog最为切入点,那么这个方法在执行前就会被SpringAop所拦截,并首先执行切面类中定义的各种通知方法,比如前置通知,异常通知等.然后再执行controller层的方法,之后还会执行Aop的后置通知,当然是你配置了后置通知的前提下…


@Controller的controller层不能被AOP拦截的问题

因为controller被JDK的动态代理代理了,所以配置文件中就应该设置成强制使用CGLB代理,配置文件如下

<!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller->  <aop:aspectj-autoproxy proxy-target-class="true" />  

利用Aop注解做日志管理

http://blog.csdn.net/czmchen/article/details/42392985

需要的类:一个log实体类/log注解类/aop类.在aop类里面进行Log的具体操作,比如进行持久化的功能等.可以实现拦截controller层和service层的方法进行做日志记录.

原创粉丝点击