码迷,mamicode.com
首页 > 编程语言 > 详细

Spring框架之Spring AOP

时间:2017-09-20 14:50:50      阅读:217      评论:0      收藏:0      [点我收藏+]

标签:roc   下标   junit   tac   exe   用户   advice   span   null   

一、基于注解管理的AOP
 
1、Spring配置文件
<!-- 配置自动扫描包,自动扫描Bean组件,切面类 -->
    <context:component-scan base-package="com.zhoujian.spring.anno,com.zhoujian.spring.test">
        <!-- <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>     -->
    </context:component-scan>
    <!-- 启动@Aspectj支持 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
 
2、切面类
package com.zhoujian.spring.aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
/**
 * 如何声明一个切面类: 首先是放入IOC容器进行管理, 其次是需要Aspect进行修饰
 *
 */
public class AuthAspectClass {
    @Before(value = "execution(* com.zhoujian.spring.anno.*.*(..))")
    // @Before("execution(* com.zhoujian.spring.test.*.*(..))")
    public void before() {
        System.out.println("模拟进行权限检查...");
    }
    @After("execution(* com.zhoujian.spring.anno.*.*(..))")
    public void after() {
        /**
         * after增强处理,不管目标方法是如何结束的,该方法会在目标方法结束之后被织入
         * 如果对同一目标方法进行了after和afterReturning增强处理且目标方法正常执行结束,
         * 此时会先织入after增强处理,之后才是afterReturning增强处理,
         * 如果目标方法非正常结束, 那么只会在目标方法结束之后,织入after增强处理,
         * 如果目标方法的非正常结束抛出了异常,伴儿会在目标方法结束之后,先织入after增强处理,
         * 之后才会织入afterThrowing增强处理
         */
        System.out.println("关闭当前事务...");
    }
    @AfterReturning(returning = "returnVal", value = "execution(* com.zhoujian.spring.anno.*.*(..))")
    public void afterReturning(Object returnVal) {
        System.out.println("目标方法的返回值:" + returnVal);
        System.out.println("只有目标方法正常执行完成后,才会执行AfterReturning...");
    }
    
    @AfterThrowing(throwing="exception",value="execution(void com.zhoujian.spring.anno.HelloImpl.getSub())")
    public void afterThrowing(Exception exception){
        System.out.println("只有执行com.zhoujian.spring.anno.HelloImpl.getSub() 该方法 ,才会进行增强");
        System.out.println("目标方法抛出的异常为: " + exception.getMessage());
        System.out.println("模拟Advice进行异常处理...");
    }
 
    
    @Around("execution(public int com.zhoujian.spring.anno.HelloImpl.total(..))")
    public Object around(ProceedingJoinPoint joinPoint){
        /**
         * Around增强处理是一个很强大,但是通常需要在一个线程安全的环境使用(比如在proceed方法调用前后需要共享数据)
         */
        Object result = null;
        try {
            Object[] args = {6,3,"4"};
            /**
             * 在这里传入一个Object数组,可以替换目标方法中的实参,偷天换日
             * 但是,传入参数的个数和类型应该与目标方法保持一致
             * 如果个数少于目标方法参数个数或者类型不匹配都会抛出异常
             * 如果是 个数多余目标方法参数个数,那么会从数组下标0开始往后取出相同个数作为实参,此时如果取出的数组元素
             * 类型与目标方法类型不匹配,那么也会抛出异常
             */
            System.out.println(joinPoint.getThis());
            System.out.println(joinPoint.getTarget());
            result = joinPoint.proceed(args);
            
        } catch (Throwable e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(result);
        /**
         * return 返回值时  也可以进行目标方法返回值的修改,偷天换日
         */
        return result;
    }
}    
3、业务类
package com.zhoujian.spring.anno;
import org.springframework.stereotype.Component;
@Component
public class HelloImpl implements Hello {
    @Override
    public void foo() {
        System.out.println("执行Hello组件的 foo()方法...");
    }
    @Override
    public int addUser(String name, String pass) {
        System.out.println("执行Hello组件的addUser()方法添加用户: " + name);
        return 10;
    }
    
    public void getSub(){
        System.out.println("执行Hello组件的getSub()方法...");
        int num = 12;
        if(num % 2 == 0){
            throw new NullPointerException("假装我是一个空指针异常...");
        }
    }
}
4、测试方法
@Test
    public void beanTest(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        HelloImpl he = ac.getBean(HelloImpl.class);
//        System.out.println(he.getClass());
        he.foo();
        he.addUser("张三", "123456");
        he.getSub();
    }
 
5、定义切入点
package com.zhoujian.spring.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspectClass {
    /**
     * 使用  @Pointcut 定义一个切入点,方法返回类型必须是void
     * 因为这仅仅只是一个签名形式的方法,为了声明切入点的名称,不需要方法体,所以方法体也为空 
     * 如果需要在其他的切面类中进行引用时,必须遵循Java的权限访问控制标准,
     * 采用类名为前缀: value="LogAspectClass.myPointcut()" 
     * 或者 pointcut="LogAspectClass.myPointcut()"
     */
    @Pointcut("execution(* com.zhoujian.spring.anno.*.*(..))")
    public void myPointcut(){}
    
    @Before(value="myPointcut()")
    public void beforeLog(){
        System.out.println("使用定义好的切入点");
    }
}
 
二、基于XML管理的AOP
 
1、Spring配置文件
 <!-- 切面类 -->
    <bean id="logAspectClassWithXML" class="com.zhoujian.spring.aspect.LogAspectClassWithXML"></bean>
    <!-- helloImpl 实现了 Hello 接口 -->
    <bean id="helloImpl" class="com.zhoujian.spring.anno.HelloImpl"></bean>
    <!-- helloImpl2 是一个单实体类,没有继承任何类和 实现任何接口 -->
    <bean id="helloImpl2" class="com.zhoujian.spring.anno.HelloImpl2"></bean>  
    <!-- fordCarChild 继承了FordCar类-->
    <bean id="fordCarChild" class="com.zhoujian.spring.anno.FordCarChild"></bean>
    
    <!-- AOP 配置 -->
    <aop:config>
        <aop:aspect id="logAspect" ref="logAspectClassWithXML" order="1">
            <aop:before method="beforeLog" pointcut="execution(* com.zhoujian.spring.anno.*.*(..))"/>
        </aop:aspect>
    </aop:config>
 
2、切面类和相关实体类
 
Hello接口
package com.zhoujian.spring.anno;
public interface Hello {
    
    public void foo();
    
    public int addUser(String name, String pass);
}
 
Hello实现类 HelloImpl
package com.zhoujian.spring.anno;
public class HelloImpl implements Hello {
    @Override
    public void foo() {
        System.out.println("执行Hello组件的 foo()方法...");
    }
    @Override
    public int addUser(String name, String pass) {
        System.out.println("执行Hello组件的addUser()方法添加用户: " + name);
        return 10;
    }
    
    public void getSub(){
        System.out.println("执行Hello组件的getSub()方法...");
        int num = 12;
        if(num % 2 == 0){
            throw new NullPointerException("假装我是一个空指针异常...");
        }
    }
    
    public int total(int a, int b){
        int total = a + b;
        return total;
    }
}
 
单实体类 HelloImpl2
package com.zhoujian.spring.anno;
public class HelloImpl2{
    public void foo() {
        System.out.println("执行Hello组件的 foo()方法...");
    }
    public int addUser(String name, String pass) {
        System.out.println("执行Hello组件的addUser()方法添加用户: " + name);
        return 10;
    }
    
    public void getSub(){
        System.out.println("执行Hello组件的getSub()方法...");
        int num = 12;
        if(num % 2 == 0){
            throw new NullPointerException("假装我是一个空指针异常...");
        }
    }
    
    public int total(int a, int b){
        int total = a + b;
        return total;
    }
}
 
切面类 LogAspectClassWithXML
package com.zhoujian.spring.aspect;
import org.apache.catalina.tribes.util.Arrays;
import org.aspectj.lang.JoinPoint;
public class LogAspectClassWithXML {
    
    public void beforeLog(JoinPoint point){
        System.out.println("Before:增强的目标方法名为:" + point.getSignature().getName());
        System.out.println("Before:增强的目标方法的参数为:" + Arrays.toString(point.getArgs()));
        System.out.println("Before:被织入增强的目标对象为:" + point.getTarget());
    }
    
    
    public void after(JoinPoint point) {
        /**
         * after增强处理,不管目标方法是如何结束的,该方法会在目标方法结束之后被织入
         * 如果对同一目标方法进行了after和afterReturning增强处理且目标方法正常执行结束,
         * 此时会先织入after增强处理,之后才是afterReturning增强处理,
         * 如果目标方法非正常结束, 那么只会在目标方法结束之后,织入after增强处理,
         * 如果目标方法的非正常结束抛出了异常,那么会在目标方法结束之后,先织入after增强处理,
         * 之后才会织入afterThrowing增强处理
         */
        System.out.println("After: 目标方法结束后释放资源...");
        System.out.println("After:增强的目标方法名为:" + point.getSignature().getName());
        System.out.println("After:增强的目标方法的参数为:" + Arrays.toString(point.getArgs()));
        System.out.println("After:被织入增强的目标对象为:" + point.getTarget());
    }
    
    public void afterReturning(JoinPoint point, Object returnVal) {
        System.out.println("AfterReturning: 获取目标方法的返回值" + returnVal);
        System.out.println("AfterReturning:增强的目标方法名为:" + point.getSignature().getName());
        System.out.println("AfterReturning:增强的目标方法的参数为:" + Arrays.toString(point.getArgs()));
        System.out.println("AfterReturning:被织入增强的目标对象为:" + point.getTarget());
    }
    
    
    public void afterThrowing(JoinPoint point, Exception exception, String name, String age){
        System.out.println("AfterThrowing: 获取到目标方法抛出的异常" + exception.getMessage());
        System.out.println("AfterThrowing:增强的目标方法名为:" + point.getSignature().getName());
        System.out.println("AfterThrowing:增强的目标方法的参数为:" + Arrays.toString(point.getArgs()));
        System.out.println("AfterThrowing:被织入增强的目标对象为:" + point.getTarget());
    }
}
 
3、测试类 AspectWithXMLTest
package com.zhoujian.spring.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zhoujian.spring.anno.HelloImpl2;
public class AspectWithXMLTest {
    @Test
    public void test() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("aspectWithXML.xml");
        System.out.println(ac.getBean("helloImpl").getClass().getName());
        /**
         * helloImpl 实体类实现了一个接口,所以其代理类的获取必须使用其实现的接口进行获取,不然会发生类型转换异常
         */
        com.zhoujian.spring.anno.Hello hel = (com.zhoujian.spring.anno.Hello) ac.getBean("helloImpl");
        hel.foo();
    }
    
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("aspectWithXML.xml");
        /**
         * 单实体类:即没有继承和实现任何类和接口的实体类, 在获取其代理对象的时候,直接获取就行了
         * 即使目标类继承了一个或者多个类,获取时正常获取即可,用其父类进行获取也行
         */
        System.out.println(ac.getBean("helloImpl").getClass().getName());
        HelloImpl2 hel = (HelloImpl2) ac.getBean("helloImpl2");
        hel.foo();
    }
}
 
注:Spring AOP 由 IOC 容器进行生成和管理,当进行IOC容器创建的时候,IOC容器会扫描切入点表达式所包含的所有包中所有类,并为所有类创建代理对象
如果目标类没有实现任何的接口,Spring将会是cglib方式创建代理对象;
如果目标类实现了一个或多个接口或者,那么Spring将会采用JDK动态代理创建代理类(此时代理类的获取必须使用接口类型接收)
 
使用Spring版本:spring-framework-4.3.10.RELEASE-dist

Spring框架之Spring AOP

标签:roc   下标   junit   tac   exe   用户   advice   span   null   

原文地址:http://www.cnblogs.com/called-j/p/7560445.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!