spring-aop学习【基于注解】

我个人觉得,这个好像就是用在定制日志输出上,和log4j很像。

用途:

如果业务方法调用每一步都需要详细的日志,那就用这个吧

好处就是:

方便维护,只包含业务代码

下面开始说明:

所需要的jar包:

com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.1.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar

直接上代码:

声明一个接口

package com.spring.bean.aop;

import java.util.List;

/**
 * 
 * @author Administrator
 *
 */
public interface UserService {
//    打招呼
    void say();
//    获取年龄
    int getValue(List<Integer> array,int index);
}

这是接口的实现类

package com.spring.bean.aop;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 
 * @author Administrator
 *      实现类
 */
@Service("userService")
public class UserServiceImpl implements UserService {

    /**
     * 自动装配use对象
     */
    @Autowired
    private User user;
    @Override
    public void say() {
        // TODO Auto-generated method stub
        System.out.println("我叫"+user.getName()+",今年"+user.getAge()+"岁,你好!!");
    }
    
    @Override
    public int getValue(List<Integer> array, int index) {
        // TODO Auto-generated method stub
        return array.get(index);
    }


}

用户对象信息

package com.spring.bean.aop;

import org.springframework.stereotype.Component;

/**
 * @author Administrator
 *      用户信息
 */
@Component
public class User {

    String name;
    int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

然后是两个切面代码

package com.spring.bean.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 声明一个切面
 * @author Administrator
 *
 */
//order可以指定哪个切面先执行,数值越小,优先执行
@Order(1) @Aspect @Component public class MyLoggingAspectj { // 声明一个切入点 @Pointcut("execution(* *(..))") public void pointcut(){ } /** * 前置通知,该方法执行在被调用方法之前 * @param joinPoint */ @Before("pointcut())") public void beforeMethod(JoinPoint joinPoint){ // 获得调用的方法名 String methodName = joinPoint.getSignature().getName(); Object[] args = joinPoint.getArgs(); System.out.println("MyLoggingAspectj the method "+methodName+"begins with "+Arrays.asList(args)); } }
第二个切面代码
package com.spring.bean.aop;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * 声明一个切面
 * @author Administrator
 *
 */
@Order(2)
@Aspect
@Component
public class LoggingAspectj {
    
    
//    声明一个切入点
    @Pointcut("execution(* *(..))")
    public void pointcut(){
        
    }

/*    *//**
     * 前置通知,该方法执行在被调用方法之前
     * @param joinPoint
     *//*
    @Before("pointcut())")
    public void beforeMethod(JoinPoint joinPoint){
//        获得调用的方法名
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("the method "+methodName+"begins with "+Arrays.asList(args));
    }
    
    *//**
     * 后置通知
     * 该方法执行在被调用方法之后,报错也依然执行
     * @param joinPoint
     *//*
    @After("pointcut())")
    public void afterMethod(JoinPoint joinPoint){
//        获得调用的方法名
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("the method "+methodName+"Ends with "+Arrays.asList(args));
    }
    
    *//**
     * 返回通知, 在方法返回结果之后执行,异常无返回值
     * @param joinPoint
     *//*
    @AfterReturning(value="pointcut())",returning="result")
    public void afterReturning(JoinPoint joinPoint,Object result){
//        获得调用的方法名
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("the method "+methodName+"afterReturning with "+Arrays.asList(args)+"  ["+result+"]");
    }
    
    *//**
     * 异常通知
     * 在方法抛出异常之后
     * @param joinPoint
     *//*
    @AfterThrowing(value="pointcut()",throwing="e")
    public void afterReturning(JoinPoint joinPoint,Exception e){
//        获得调用的方法名
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("the method "+methodName+"afterThrowing with "+Arrays.asList(args)+e);
    }*/
    
    /**
     * 环绕通知需要配合ProceedingJoinPoint使用,相当于动态代理
     * @param pjp
     * @return
     */
    @Around(value="pointcut()")
    public Object aroundMethod(ProceedingJoinPoint pjp) {
        // 获得调用的方法名
        String methodName = pjp.getSignature().getName();
        Object result = null;
        // 调用目标方法
        try {
            // 前置通知
            System.out.println("the method " + methodName + "Begins with " + Arrays.asList(pjp.getArgs()));
            result = pjp.proceed();
            // 后置通知
            System.out.println("the method " + methodName + "Ends with " + Arrays.asList(pjp.getArgs()));
            // 后置有返回值
            System.out.println(
                    "the method " + methodName + "Ends with " + Arrays.asList(pjp.getArgs()) + " [" + result + "]");
        } catch (Throwable e) {
            // TODO Auto-generated catch block
            // 异常通知
            System.out.println("the method " + methodName + "AfterThrowing with " + Arrays.asList(pjp.getArgs()) + e);
            // e.printStackTrace();
            // 不加这句,会报错,因为result返回值为null
            throw new RuntimeException(e);
        }
        System.out.println("the method " + methodName + "LastEnds with " + Arrays.asList(pjp.getArgs()));
        return result;
    }
    
    
}

测试代码:

package com.spring.bean.aop;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ApplicationContext ctx=new ClassPathXmlApplicationContext("bean-aop.xml");
        UserService userServiceImpl=(UserService) ctx.getBean("userService");
        User user=(User) ctx.getBean("user");
        List<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(1);
        arrayList.add(2);
        int age = userServiceImpl.getValue(arrayList, 1);
        user.setName("xiaoqiang");
        user.setAge(age);
        userServiceImpl.say();
    }

}

bean文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <!-- 自动扫描的包 -->
    <context:component-scan base-package="com.spring.bean.aop"></context:component-scan>
    <!-- 使 AspectJ 的注解起作用 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
 总结:
1.在pom文件添加依赖,在 Spring 的配置文件中加入 aop 的命名空间。 
    <!--使用AspectJ方式注解需要相应的包-->  
         <dependency>  
            <groupId>org.aspectj</groupId>  
            <artifactId>aspectjrt</artifactId>  
            <version>${aspectj.version}</version>  
        </dependency>  
         <!--使用AspectJ方式注解需要相应的包-->  
        <dependency>  
            <groupId>org.aspectj</groupId>  
            <artifactId>aspectjweaver</artifactId>  
            <version>${aspectj.version}</version>  
        </dependency> 

2.为接口实现类添加注解@Component

3.编写一个切面类,配置切面

* 3.1 在配置文件中配置自动扫描的包: <context:component-scan base-package="com.spring.bean.aop"></context:component-scan>

* 3.2 加入使 AspjectJ 注解起作用的配置: <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
* 为匹配的类自动生成动态代理对象.

4.编写前置通知方法,在方法上方添加注解

// 表达式注意格式: 修饰 +方法(有无返回)+包名+类名+方法名+参数


  @Before("execution(public int com.spring.bean.annotation.aopimpl.Calculation.sub(int, int))")

* @Before 表示在目标方法执行之前执行 @Before 标记的方法的方法体.
* @Before 里面的是切入点表达式:

如关注详细参数,添加joinpoint对象,可以访问到方法的签名和参数

原文地址:https://www.cnblogs.com/longronglang/p/6243251.html