spring AOP的两种配置方式

Posted Rainyn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring AOP的两种配置方式相关的知识,希望对你有一定的参考价值。

 

  连接点(JoinPoint) ,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点。

 

方式一:xml方式配置

1.配置xml文件

    <bean id="dataSourceExchange" class="com.ooper.www.datasource.DataSourceExchange"/> <!--辅助功能bean-->
    <aop:config>
        <aop:pointcut id="dataSourcePointcut" expression="execution(* com.ooper.www.service.Impl.AccountServiceImpl.*(..))"/> <!-- 指定核心业务功能 -->
        <aop:aspect ref="dataSourceExchange"> <!--指定辅助功能  -->
            <aop:before pointcut-ref="dataSourcePointcut" method="before"/><!-- 执行核心任务之前执行 -->
            <aop:after pointcut-ref="dataSourcePointcut" method="after"/><!-- 执行核心任务之后执行 -->
        </aop:aspect>
    </aop:config>

2. 辅助功能java代码

package com.ooper.www.datasource;
import org.aspectj.lang.JoinPoint;

public class DataSourceExchange {

    public void before(JoinPoint point) {

        //获取目标对象的类类型
        Class<?> aClass = point.getTarget().getClass();
        String c = aClass.getName();
        String[] ss = c.split("\\.");
        //获取包名用于区分不同数据源
        String methodName = ss[5];

        if ("AccountServiceImpl".equals(methodName)) {
            DataSourceHolder.setDbType(DataSourceEnum.DS2.getKey());
            System.out.println("数据源:"+DataSourceEnum.DS2.getKey());
        } else {
            DataSourceHolder.setDbType(DataSourceEnum.DS1.getKey());
            System.out.println("数据源:"+DataSourceEnum.DS1.getKey());
        }
    }

    /**
     * 执行后将数据源置为空
     */
    public void after(JoinPoint point) {
      System.out.println("point:" + point);
      DataSourceHolder.setDbType(null);
    }
}

方式二:注解方式

1.xml配置文件

      <!-- 注解方式实现AOP -->
  
      <!-- 激活自动代理功能   --> 
      <!-- 代理方式1:采用JDK代理 -->
        <aop:aspectj-autoproxy/> 
        <!--     代理方式2:cglib代理 -->
        <!--     <aop:aspectj-autoproxy proxy-target-class="true"/>   -->
        <!-- 找到被注解了的切面类,进行切面配置 -->
        <context:component-scan base-package="com.how2java.aspect"/>
        <context:component-scan base-package="com.how2java.controller"/>

2.注解配置切面代码

package com.how2java.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**spring AOP
此段小代码演示了spring aop中@Around @Before @After三个注解的区别
 * @Before是在所拦截方法执行之前执行一段逻辑。@After 是在所拦截方法执行之后执行一段逻辑。@Around是可以同时在所拦截方法的前后执行一段逻辑。
 * @author Administrator
 * 通过aop拦截后执行具体操作
 */
@Aspect
@Component
public class LogIntercept {

//    @Pointcut("execution(* com.how2java.controller..*.*(..))")
    public void recordLog(){}

    @Before("execution(* com.how2java.controller..*.*(..))")
//    @Before("recordLog()")
    public void before() {
        this.printLog("已经记录下操作日志@Before 方法执行前");
    }

    @Around("execution(* com.how2java.controller..*.*(..))")
//    @Around("recordLog()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        this.printLog("已经记录下操作日志@Around 方法执行前");
        Object obj = pjp.proceed();
        this.printLog("已经记录下操作日志@Around 方法执行后");
        return obj;
    }

     @After("execution(* com.how2java.controller..*.*(..))")
//    @After("recordLog()")
    public void after() {
        this.printLog("已经记录下操作日志@After 方法执行后");
    }

    private void printLog(String str){
        System.out.println(str);
    }
}
package com.how2java.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
 
@Aspect    // 注解表示这是一个切面
@Component //表示这是一个bean,由Spring进行管理,使用注解时一定要使用@component或者@Repository、@Controller、@Service中一个去声明,将切面类放入到spring容器中,不然就去xml中显式写一个bean,不然的话就会报错,无法实现切面功能。

public class LoggerAspect { 
    @Around(value = "execution(* com.how2java.controller..*.*(..))") 
  //表示对com.how2java.controller 这个包中的所有方法进行切面操作
    /*    AOP(execution表达式)
     * 
     * execution(* com.how2java.controller..*.*(..))
        解释如下:
        符号                                                                           含义
        execution()                        表达式的主体;
        第一个”*“符号                                  表示返回值的类型任意;
        com.how2java.controller        AOP所切的服务的包名,即,我们的业务部分
        包名后面的”..“                                               表示当前包及子包
        第二个”*“                                                         表示类名,*即所有类。此处可以自定义,下文有举例
        .*(..)                                                         表示任何方法名,括号表示参数,两个点表示任何参数类型
        
        */
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("start log:" + joinPoint.getSignature().getName());
        Object object = joinPoint.proceed();//就是将来与某个核心功能编织之后,用于执行核心功能的代码
        System.out.println("end log:" + joinPoint.getSignature().getName());
        return object;
    }
}

 

以上是关于spring AOP的两种配置方式的主要内容,如果未能解决你的问题,请参考以下文章

Spring读源码系列之AOP--08--aop执行完整源码流程之自动代理创建器导入的两种方式

Spring系列之AOP实现的两种方式

AOP的两种实现方式

java的动态代理的两种方式和spring的aop面向切面编程的对比

Spring之AOP理解及使用

Spring的IOC容器加载