博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring之AOP
阅读量:6230 次
发布时间:2019-06-21

本文共 5172 字,大约阅读时间需要 17 分钟。

   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的信息:

        定义接口类:

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@Componentpublic 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的实现类增加一些方法。

   

  或者进行如下的配置:

   

         

转载于:https://www.cnblogs.com/lnlvinso/p/4001972.html

你可能感兴趣的文章
了解一下Elasticsearch的基本概念
查看>>
二、let变量声明方式介绍
查看>>
iOS逆向:在任意app上开启malloc stack追踪内存来源
查看>>
【BZOJ】4033: [HAOI2015]树上染色 树上背包
查看>>
python学习三:列表、元组、字典、集合
查看>>
iOS中使用UISegmentControl进行UITableView切换
查看>>
自适应响应式,手机,平板,PC,java企业网站源码
查看>>
【CodeForces】835F Roads in the Kingdom
查看>>
2014.4.17—openflow代码流程
查看>>
leetcode-414-Third Maximum Number
查看>>
最新Android开源库、工具、开源项目整理分享
查看>>
Sql 获取当前日期没有时分秒
查看>>
mybatis_mapper动态代理
查看>>
CoreData一些基本概念
查看>>
1.java soap api操作和发送soap消息
查看>>
AJAX请求 $.ajaxSetup方法的使用
查看>>
background-size搭配transition实现鼠标hover背景图放大问题
查看>>
Redis分布式锁
查看>>
spark/java连接 kudu incompatible RPC? Error is: step 异常解决
查看>>
流程控制、数据类型(列表)
查看>>