zoukankan      html  css  js  c++  java
  • Spring -- aop, 用Aspectj进行AOP开发

    1. 概要

    添加类库:aspectjrt.jaraspectjweaver.jar
    添加aop schema.
    定义xml元素:<aop:aspectj-autoproxy>
    编写java,并用@Aspect注解成通知

         AspectJ 支持 5 种类型的通知注解:

      @Before: 前置通知,在方法执行之前执行

      @After: 后置通知,在方法执行之后执行

      @AfterRunning: 返回通知,在方法返回结果之后执行

      @AfterThrowing: 异常通知,在方法抛出异常之后

      @Around: 环绕通知,围绕着方法执行

    配置成普通bean元素即可.
     

    前置通知:@Before

    @Aspect

    public class AudienceAdvice {

      @Before("execution(* WelcomeService.*(..))")

      public void takeSeats(){..}

       @Before("execution(* WelcomeService.*(..))")

      public void turnOffCellphone(JoinPoint jp){..}

    JoinPoint参数可访问连接点细节,入方法名和参数等.

    jp.getTarget()//目标对象

    jp.getThis()//当前的代理对象

    jp.getArgs();//方法调用参数

    jp.getSignature().getName()//方法签名

    后置通知:@After

        @After("execution(* *..WelcomeService.*(..))")

        public void applaud(){..}

    后置通知在目标方法执行完成之后执行.一个切面aspect包含很多通知.

    @After

        后置通知表明目标方法执行完之后,不论是否抛异常,都会织入该通知.

    @AfterReturning

        方法返回后通知只在目标方法返回以后执行,若抛异常不执行.

    @AfterReturning(pointcut="",returning="res")

    public void xxx(Joinput jp,Object res)

    在后置通知中可接收到返回值.res即是用来接收返回值的对象.

    环绕通知:@Around

        @Around("execution(* *..WelcomeService.*(..))")

        public void around(ProceedingPointCut jp){..}

    注意:可以控制目标方法是否调用,以及返回完全不同的对象,要慎用.

    指定优先级:

    @Aspect

    @Order(0)

    public class xxx{...}

    加上@Order注解可以指定加入切面的优先级(先后顺序,值越小,优先级越高)

    引入通知:

    @Aspect

    public class MyAspectjIntroduction {

      @DeclareParents(value="*..*Service*",

                       defaultImpl=ModifyDateImpl.class)

      private ModifyDate md ;

    }

    value:指定哪些类可以应用该属性

    defaultImpl:指定接口的实现类

    典型Aspectj切入点表达式定义:

    execution(* cn.itcast.WelcomeServiceImpl.*(..))

    execution(public * *..WelcomeServiceImpl.*(..))

    execution(public void *..WelcomeServiceImpl.*(..))

    execution(public void *..*Service.*(double,double))..

    切入点表达式运算(&& || !)

    @Pointcut("execution(..) || execution(..)")

    2. 示例代码:

    Performer.java 演员接口

    public interface Performer {
    	public void show();
    }

    Singer.java 接口实现

    public class Singer implements Performer {
    	public void show() {
    		System.out.println("其实我是个演员!");
    //		String str = null ;
    //		str.toString();
    	}
    }

    Audience.java 观众类, 即通知类

    package cn.itcast.spring.aop.aspectj;
    
    import org.aspectj.lang.JoinPoint;
    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.aspectj.lang.annotation.DeclareParents;
    import org.aspectj.lang.annotation.Pointcut;
    
    /**
     * 观众, 需要添加 @Aspect
     */
    @Aspect
    public class Audience {
    	
    	/**
    	 * 引入通知,
    	 */
    	@DeclareParents(value="cn.itcast.spring.aop.aspectj.Singer",defaultImpl=ModifyDateImpl.class)
    	private ModifyDate md ;
    	/**
    	 * 定义在切入点, 切入点表达式
    	 */
    	//任意返回值  Performer中 任意方法 任意参数 
    	@Pointcut("execution(* cn.itcast.spring.aop.aspectj.Performer.*(..))")
    	public void perform(){
    	}
    	/**
    	 * 坐好
    	 */
    	@Before(value="perform()")
    	public void takeSeat(){
    		System.out.println("takeSeat");
    	}
    	
    	/**
    	 * 关机
    	 */
    	@Before(value="perform()")
    	public void turnOffCellphone(JoinPoint jp){
    		System.out.println(jp.getSignature().getName());
    		System.out.println(jp.getArgs());
    		System.out.println(jp.getTarget());
    		System.out.println(jp.getThis());
    		System.out.println("turnOffCellphone");
    	}
    	
    	/**
    	 * returning:指定哪个参数接受方法的返回值
    	 */
    	@AfterReturning(pointcut="perform()",returning="ret")
    	public void applaud(Object ret){
    		System.out.println("applaud");
    		System.out.println("ret = " + ret);
    	}
    	
    	/**
    	 * 退票
    	 * throwing:指定哪个参数接受异常信息
    	 */
    	@AfterThrowing(pointcut="perform()",throwing="e")
    	public void demandMoney(Exception e){
    		System.out.println("demandMoney");
    		System.out.println("出事了 " + e.getMessage());
    	}
    	
    	@After("perform()")
    	public void goHome(){
    		System.out.println("goHome");
    	}
    	
    	/*
    	* 环绕通知
    	*/
    	@Around(value="perform()")
    	public Object watch(ProceedingJoinPoint pjp){
    		try {
    			System.out.println("takeSeat");
    			System.out.println("turnOffCellphone");
    			Object o = pjp.proceed();
    			System.out.println("applaud");
    			return o;
    		} catch (Throwable e) {
    			System.out.println("demandMoney");
    		}
    		finally{
    			System.out.println("goHome");
    		}
    		return null ;
    	}
    }
    

    ModifyDate.java 引入通知接口

    /**
     * 修改日期
     */
    public interface ModifyDate {
    	public void setModifyDate(Date date);
    	public Date getModifyDate();
    }

    ModifyDateImpl.java 引入通知实现

    public class ModifyDateImpl implements ModifyDate {
    	private Date date ;
    	public Date getModifyDate() {
    		return date;
    	}
    
    	public void setModifyDate(Date date) {
    		this.date = date ;
    	}
    }

    aspectj.xml 配置文件

    <?xml version="1.0"?>
    <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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">
        <!-- 观众通知 -->
        <bean id="audience" class="cn.itcast.spring.aop.aspectj.Audience" />
        
        <!-- 歌手 -->
        <bean id="singer" class="cn.itcast.spring.aop.aspectj.Singer" />
        
        <!-- 使用aspectj自动产生代理 -->
        <aop:aspectj-autoproxy />
    </beans>

    App.java 测试代码

    public class App {
    	public static void main(String[] args) {
    		ApplicationContext ac = new ClassPathXmlApplicationContext(
    				"cn/itcast/spring/aop/aspectj/aspectj.xml");
    		Performer p = (Performer) ac.getBean("singer");
    		p.show();
    		//测试引入通知
    		((ModifyDate)p).setModifyDate(new Date());
    		System.out.println(((ModifyDate)p).getModifyDate());
    	}
    }


    3. 使用pojo+xml开发aop

    基于注解的aspectj声明优先于xml配置.基于xml的配置是spring专有的.aspectj得到越来越多的支持,具备更好的重用性.

    其他bean 和 通知类 都不会改变, 只会不再需要用注解, 改用xml文件

    pojo.xml 引入通知, 前置 后置 异常通知

    <?xml version="1.0"?>
    <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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">
        <!-- 观众 -->
        <bean id="audience" class="cn.itcast.spring.aop.pojo.Audience" />
        <!-- 歌手 -->
        <bean id="singer" class="cn.itcast.spring.aop.pojo.Singer" />
        
        <!-- aop配置 -->
        <aop:config>
            <aop:aspect ref="audience">
                <!-- 引入通知 -->
                <aop:declare-parents types-matching="cn.itcast.spring.aop.pojo.Singer"
                                     implement-interface="cn.itcast.spring.aop.pojo.ModifyDate"
                                     default-impl="cn.itcast.spring.aop.pojo.ModifyDateImpl"/>
                <!-- 单独定义切入点表达式 -->
                <aop:pointcut id="audiencePointcut" expression="execution(* cn.itcast.spring.aop.pojo.Performer.*(..))"/>
                
                <!-- 前置通知 -->
                <aop:before method="takeSeat" pointcut-ref="audiencePointcut" />
                <aop:before method="turnOffCellphone" pointcut-ref="audiencePointcut"/>
                
                <!-- 后置通知,ret指定哪个参数接受返回值 -->
                <aop:after-returning method="applaud" pointcut-ref="audiencePointcut" returning="ret"/>
                
                <!-- throwing:指定哪个参数接受异常信息 -->
                <aop:after-throwing method="demandMoney" pointcut-ref="audiencePointcut" throwing="ex"/>
                
                <!--  -->
                <aop:after method="goHome" pointcut-ref="audiencePointcut"/>
            </aop:aspect>
        </aop:config>
    </beans>

    pojoAround.xml 环绕通知

    <?xml version="1.0"?>
    <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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd ">
        <!-- 观众 -->
        <bean id="audience" class="cn.itcast.spring.aop.pojo.AudienceAround" />
        <!-- 歌手 -->
        <bean id="singer" class="cn.itcast.spring.aop.pojo.Singer" />
        
        <!-- aop配置 -->
        <aop:config>
            <aop:aspect ref="audience">
                <aop:around method="watch" pointcut="execution(* cn.itcast.spring.aop.pojo.Performer.*(..))"/>
            </aop:aspect>
        </aop:config>
    </beans>



     





     

  • 相关阅读:
    07.31《jQuery》——3.2文件上传、添加删除文件域
    07.31《jQuery》——3.1jQuery实现DOM节点的增删改
    07.30《jQuery》——2.2使用键盘上下左右键控制div框
    07.30《jQuery》——2.1div框的移动
    07.30《jQuery》——2.1隔行换色_简单的选择器练习
    【leetcode 530】刷题问题
    数据库基本概念之事务与并发控制
    我的LaTeX中文文档模板
    vim的使用与配置
    LaTeX简单使用方法
  • 原文地址:https://www.cnblogs.com/xj626852095/p/3648144.html
Copyright © 2011-2022 走看看