SpringAOP的几种配置

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层的方法进行做日志记录.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值