zoukankan      html  css  js  c++  java
  • Spring之AOP

       1.基本概念 

          日志,安全和事务管理都是AOP可以应用的地方。

          

      应用AOP之后,日志的代码,安全的代码,事务的代码不会散落在各个模块,由Spring的AOP统一管理。如果通用的行为不满足,比如日志的级别不同,也可以自己按照需求再写一次即可。

       

      Spring中的AOP是通过动态代理来实现的,类是继承于接口的会调用JDK的动态代理,否则使用CGLIB。完成代理的动作是在运行期动态完成的。

     

       Spring AOP,AspectJ和JBoss是AOP的三个主要的框架。Spring只支持对方法进行拦截,而AspectJJBoss还支持对属性和构造函数的拦截。如果希望拦截到属性的变化,可以在Spring中引入AspectJ

        2.切点

      切点和通知是切面的最基本的元素。

      分布于应用中多处的功能被称为横切关注点,例如上图中的内容服务、计费服务等。
      切点参数的含义:
      execution(* com.spring.service.AService.*(..))
      第一个*表示任意的返回类型,com.spring.service.AService指定了一个接口,第二*表示包含接口的任意方法,..表示任意的参数类型。指定了接口AService,则对实现了接口的任意子类都包含在内。

           execution(* com.spring.service..*.*(..))

          和上面的进行比较,第一个*表示任意的返回类型,第一个..表示com.spring.service及其子包都将被拦截,*.*代表任意类的任意方法,第二个..表示任意的参数类型

          
      execution(* com.spring.service.AService.*(..)) && within(com.spring.service.impl.*)
      表示同时要是com.spring.service.impl包下面的AService接口的实现类。表达式间的操作符包括&&,||,!或者and,or,not。

      execution(!void com.spring.service.AService.*(java.lang.String,..)) ,第一个参数为String,后面可为任意个数,任意类型的参数。返回类型不为void。


      如果需要知道一个方法执行花费了多长时间,环绕通知是很合适来完成的。环绕通知还很适合于做权限控制。
      为切点增加参数信息execution(* com.spring.service.AService.*(java.lang.String)) and args(thoughts),将AService实现类方法中的String类型的thoughts作为参数传递给拦截器,可以获取方法的输入参数。

           还可以将切点写为execution(* com.spring.service.AService.*(..)),再在具体的方法上加上输入参数,如:

           @Before("anyMethod() && args(name))   //与方法的参数 名称name要一致

           public void accessCheck(String name),作用相当于取交集,先满足切点条件,再要满足输入参数是唯一的,且为String类型,类似add(String name,Integer id)的方法将不会被拦截。

          

          上面是获取方法的输入参数,下面的是获取方法的返回结果的实例:    

          @Before(pointcut = "anyMethod() ", returning = "result")   //与方法的参数 名称result要一致

          public void accessCheck(String result)

       3.通知的概念

         

       

         通知是指在执行横切关注点中的方法时,在执行动作的前,后等要执行的一些动作,如记录日志,调用事务等。

         对应于配置文件中的标签如下:

       

      4.基于XML的AOP实现

        

           aop:aspect ref ="audience",表示切点要依赖于id为audience的bean,各种通知也是在id为audience的bean中定义的。

      获取输入的参数:

         

     5.基于注解的AOP实现

         

       使用注解时@Pointcut需要依附于一个方法,方法本身不重要,可以是空实现。

          基于注解及自动扫描实现IoC和AOP。

          配置文件contextByAspect.xml的信息:

    <?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" xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/aop   
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    ">
        <context:annotation-config /> 
        <!-- 自动扫描(自动注入) -->
        <context:component-scan base-package="com.spring..*"/> 
        <aop:aspectj-autoproxy/>
        
    </beans>

            定义接口类:

    package com.spring.service;
    /**
     * 接口A
     */
    public interface AService {
        
        public void fooA(String _msg);
    
        public void barA();
    }
    

      定义实现类:

    package com.spring.service.impl;
    
    import org.springframework.stereotype.Component;
    import com.spring.service.AService;
    
    /**
     *接口A的实现类
     */
    @Component("aService")
    public class AServiceImplByAspect implements AService {	
    	public AServiceImplByAspect(){
    		System.out.println("a begin!");
    	}
    	
        public void barA() {
            System.out.println("AServiceImpl.barA()");
        }
    	
        public void fooA(String _msg) {
            System.out.println("AServiceImpl.fooA(msg:"+_msg+")");
        }
    }
    

      定义切面package com.spring.aopimport org.aspectj.lang.JoinPoint;

    import org.aspectj.lang.ProceedingJoinPoint;
    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 TestAspectByAspect {
    	@Pointcut(value = "execution(* com.spring.service.AService.*(..))") 
    	public void before(){
    		
    	}
    	
        public void doAfter(JoinPoint jp) {
            System.out.println("log Ending method: "
                    + jp.getTarget().getClass().getName() + "."
                    + jp.getSignature().getName());
        }
    
        public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
            long time = System.currentTimeMillis();
            Object retVal = pjp.proceed();
            time = System.currentTimeMillis() - time;
            System.out.println("process time: " + time + " ms");// if(拥有权限){
            // Object retVal = pjp.proceed();
    //}else{

    //
    //}return retVal;
        }
        
        @Before(value = "before()")
        public void doBefore(JoinPoint jp) {
            System.out.println("log Begining method: "
                    + jp.getTarget().getClass().getName() + "."
                    + jp.getSignature().getName());
        }
    
        public void doThrowing(JoinPoint jp, Throwable ex) {
            System.out.println("method " + jp.getTarget().getClass().getName()
                    + "." + jp.getSignature().getName() + " throw exception");
            System.out.println(ex.getMessage());
        }
    
        private void sendEx(String ex) {
            //TODO 发送短信或邮件提醒
        }
    } 
    

      定义单元测试类:

    package com.spring.test;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.stereotype.Component;
    import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
    import com.spring.service.AService;
    import com.spring.service.impl.BServiceImplByAspect;
    
    
    public class AOPTestByAspect extends AbstractDependencyInjectionSpringContextTests {
    	@Autowired(required = false)
    	private  AService aService;
    	
    
    	protected String[] getConfigLocations() {
    		String[] configs = new String[] { "/contextByAspect.xml"};
    		return configs;
    	}
    	
    	/**
    	 * 测试正常调用
    	 */
    	public void testCall()
    	{
    		System.out.println("SpringTest JUnit test");
    		aService.fooA("JUnit test fooA");
    		aService.barA();
    	}
    	
    	
    	public void setAService(AService service) {
    		aService = service;
    	}
    	
    }
    

        SpringAOP是基于代理的,如果所需求的功能超出了Spring的代理功能,就可考虑AspectJ的使用。

       

       6.使用AOP动态的为类添加方法

          前面的都是在拦截的方法前后做一些事情,下面的配置可以动态地为接口Perfomer的实现类增加一些方法。

       

      或者进行如下的配置:

       

             

  • 相关阅读:
    [转]xna 3.1 to xna 4.0
    office 2010 激活信息查看
    Windows 8 Release Preview下载地址
    常用书籍推荐与下载地址
    禁用Windows7脱机文件的方法
    [转]DEM数据和影像数据下载汇总
    打工是最愚蠢的投资——李嘉诚在深圳大梅沙演讲
    j截图Code
    BYTE与_int64转换
    英语中of和for用法有什么区别?
  • 原文地址:https://www.cnblogs.com/lnlvinso/p/4001972.html
Copyright © 2011-2022 走看看