zoukankan      html  css  js  c++  java
  • Spring中AOP的使用

    问题:什么是AOP?

    答:AOP基本概念:Aspect-Oriented Programming,面向方面编程的简称,Aspect是一种新的模块化机制。用来描写叙述分散在对象、类或方法中的横切关注点(crosscutting concern), 从关注点中分离出横切关注点是面向方面程序设计的核心所在。

    分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特 定领域问题代码的调用。业务逻辑同特定领域问题的关系通过方面来封装、维护,这样原本分散在整个应用程序中的变动就能够非常好地管理起来。

    个人理解:所谓的AOP就是把我们的程序的运行看成是一个方块的面包,然后切成了一片一片的吐司--这些吐司就是我们一个一个的方法。

    然后在这些吐司片的前面,后面、甚至是里面来做一些特定条件下发生的特定事情。比方嵌入几个葡萄干、给前面加苹果酱、给后面加草莓酱这种事情。。优势在于你能够在自己的AOP方法中规定一个加苹果酱的理由,满足这个理由的话就能够加苹果酱,而不用在每一个方法中都特定的指出加苹果酱,加草莓酱什么的··个人理解···。


    AOP的实现有非常多的方式。我这边使用Spring中自带的aop来做一些业务逻辑的实现。

    在Spring中实现aop的方式有两种。各自是通过xml配置和通过注解配置。以下来介绍这两种方式。

    在介绍他们之前先看一下项目的结构:


    上图中ServiceAspect是我们使用注解的方式来实现AOP的类,InteceptorXML是使用XML来实现AOP的类;TestAop是測试方法;TestServiceImpl;TestService是用来被AOP的动作。(须要明白的是,AOP的动作建议都发生在service层面。

    )application-context.xml是我的配置文件。

    1.通过注解配置。

    我注解AOP的代码例如以下:

    package test.aop;
    
    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.stereotype.Component;
    
    import test.entity.User;
    
    @Component
    // 声明这是一个组件
    @Aspect
    // 声明这是一个切面bean
    public class ServiceAspect {
    
    	// 配置切入点,该方法无方法体,主要是为了同类中其它方法使用此处配置的切入点   ----见(1)
    	@Pointcut("execution(* test.service..*.*(..))")
    	public void aspect() {
    	}
    
    	// 配置前置通知,使用在方法aspect()上注冊的切入点,同一时候接受JoinPoint切入点对象。能够没有该參数  ----见(2)
    	@Before("aspect()&&args(id)")
    	public void before(JoinPoint joinPoint, long id) {
    		System.out.println(id + "------------------");
    		System.out.println("before-->" + joinPoint);
    	}
    
    	// 配置后置通知,使用在方法aspect()上注冊的切入点----见(3)
    	@After("aspect()&&args(id)")
    	public void after(JoinPoint joinPoint, long id) {
    		System.out.println(id + "after----------------------");
    		System.out.println("after-->" + joinPoint);
    	}
    
    	// 配置围绕通知----见(4)
    	@Around("aspect()")
    	public Object around(JoinPoint joinPoint) {
    		long start = System.currentTimeMillis();
    
    		try {
    			Object o=((ProceedingJoinPoint) joinPoint).proceed();
    			User user = (User)o;
    			System.out.println("-----around======="+user.toString());
    			long end = System.currentTimeMillis();
    			System.out.println("around -->" + joinPoint + "	Use time : "
    					+ (end - start) + " ms!");
    			return user;
    		} catch (Throwable e) {
    			long end = System.currentTimeMillis();
    			System.out.println("around __>" + joinPoint + "	Use time : "
    					+ (end - start) + " ms with exception : " + e.getMessage());
    			return null;
    		}
    
    	}
    
    	// 配置后置返回通知,使用在方法aspect()上注冊的切入点----见(5)
    	@AfterReturning(pointcut = "aspect()", returning = "returnVal")
    	public void afterReturning(JoinPoint joinPoint, Object returnVal) {
    		System.out.println("afterReturning executed, return result is "
    				+ returnVal);
    	}
    
    	// 配置抛出异常后通知,使用在方法aspect()上注冊的切入点----见(6)
    	@AfterThrowing(pointcut = "aspect()", throwing = "ex")
    	public void afterThrow(JoinPoint joinPoint, Exception ex) {
    		System.out.println("afterThrow--> " + joinPoint + "	"
    				+ ex.getMessage());
    	}
    }
    


    非常多内容在凝视中已经有了。这里说一下几个关键的easy让人不明确的地方。

    (1)@Pointcut("execution(* test.service..*.*(..))")就是我们定义的切入点,在括号中面的參数是指定了哪些方法是在考虑切入的范围内的;

    * test.service..*.*(..)能够这样来解剖:

    第一个* :表示被拦截的方法能够是随意的返回类型;

    test.service:指定了要拦截的包。

    ..:这两个..表示的是被指定的拦截包test.service中全部的子包中的类的方法都要考虑到拦截的范围中;

    *:表示随意的类。

    .*:表示随意的方法;

    (..):表示随意的方法參数;

    总结起来,就是告诉我们这样一个信息:要拦截test.service中全部子包中的全部类的全部方法,这些方法的返回值能够是随意的,參数能够是随意的。

    当然,我们也能够特定很多内容。可是格式不要变。比如:

    @Pointcut(“execution(* test.service..*.add*(..))”)

    那么所要拦截的方法就必须以add来开头了。

    切入点的方法中不实现不论什么的操作,作用仅仅是提供给其它的切面来使用。


    (2)

    @Before("aspect()&&args(id)")中的 aspect(),指定指定切入点的方法。就是我们定义为pointCut的aspect()方法,然后args(id),我们获取了所拦截的方法的传入的參数中的id;在before方法中我们能够在切入点运行曾经来做一些操作。 当中的joinPoint是切入点的相关信息。


    (3)

    @After("aspect()&&args(id)")同(2)。仅仅是这是在切入点运行完毕以后来做出一些处理。


    (4)

    @Around("aspect()")是围绕通知,在围绕通知中我们能切入点的非常多内容进行改动;

    当中通过Object o=((ProceedingJoinPoint) joinPoint).proceed();我们就能够让切入点的方法完毕,获得他的执行结果。

    然后User user = (User)o;我们把它转换为User对象。假设在return user,之前我们加上user.setName("after aa");就能够改变切入点的执行结果。

    这样的操作对于非常多的错误检測以及格式检測是非常实用处的。


    (5)

    @AfterReturning(pointcut = "aspect()", returning = "returnVal")

    这里是切入点有返回结果后做的操作。通过returning的定义我们能获得切入点的返回结果;


    (6)

    @AfterThrowing(pointcut = "aspect()", throwing = "ex")

    这里能够在切入点抛出异常后做一些工作,通过定义throwing我们能获得抛出的异常对象。


    相关代码:

    application-context.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:p="http://www.springframework.org/schema/p"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"
    	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
    	xmlns:aop="http://www.springframework.org/schema/aop"
    	xsi:schemaLocation="
            http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util-3.0.xsd
            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/tx 
            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    		http://www.springframework.org/schema/jee 
    		http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <context:component-scan base-package="test"> <!--开启spring自己定义的包扫描,我定义的为扫描test包下全部内容-->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/><!--这里不扫描controller。在mvc中扫描,安全又可靠-->
    </context:component-scan>	
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy><!--开启凝视方式的spring aop-->
    <bean id="userService" class="test.service.impl.UserService"></bean><!--注入userService-->
    </beans>

    UserService

    package test.service.impl;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import test.entity.User;
    
    public class UserService {
    	private final static Log log = LogFactory.getLog(UserService.class);
    
    	public User get(long id) {
    		if (log.isInfoEnabled()) {
    			log.info("getUser method . . .");
    		}
    		User user = new User(1, "test");
    		return user;
    	}
    
    	public void save(User user) {
    		if (log.isInfoEnabled()) {
    			log.info("saveUser method . . .");
    		}
    	}
    
    	public boolean delete(long id) throws Exception {
    		if (log.isInfoEnabled()) {
    			log.info("delete method . . .");
    			throw new Exception("spring aop ThrowAdvice演示");
    		}
    		return false;
    	}
    }
    


    test方法

    package demo;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import test.entity.User;
    import test.service.impl.UserService;
    
    public class TestAop {
    	
    	public static void main(String[] args) {
    		ApplicationContext aContext = new ClassPathXmlApplicationContext("application-context.xml");//载入spring文件
    		UserService userService = (UserService) aContext.getBean("userService");//获得userservice
    		User user =userService.get(1L);//调用get方法。
    		System.out.println(user);
    		try {
    			userService.delete(1L);//调用delete方法。
    		} catch (Exception e) {
    				System.out.println("Delete user : " + e.getMessage());
    		}
    	}
    }
    


    測试结果:




    2.通过XML来配置

    通过xml来配置AOP,操作都在xml文件里完毕

    在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:p="http://www.springframework.org/schema/p"
    	xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"
    	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
    	xmlns:aop="http://www.springframework.org/schema/aop"
    	xsi:schemaLocation="
            http://www.springframework.org/schema/util
            http://www.springframework.org/schema/util/spring-util-3.0.xsd
            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/tx 
            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    		http://www.springframework.org/schema/jee 
    		http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <!-- <context:component-scan base-package="test">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>	
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> -->
    <bean id="userService" class="test.service.impl.UserService"></bean>
    
    <bean id="inteceptorXML" class="test.aop.InteceptorXML"></bean>
    <aop:config>
    <aop:aspect id="aspectd" ref="inteceptorXML">
    <aop:pointcut expression="execution(* test.service..*.*(..))" id="mypointCutMethod"/>
    <aop:before method="doAccessCheck" pointcut-ref="mypointCutMethod" />
    </aop:aspect>
    </aop:config>
    </beans>



    在xml中我们指定了用来作为拦截器的bean----inteceptorXML,类似的指定了切入点

    <aop:aspect id="aspectd" ref="inteceptorXML">指定了拦截器为interceptorXML。


    execution(* test.service..*.*(..)),并指定了id为mypointCutMethod。然后定义了
    <aop:before method="doAccessCheck" pointcut-ref="mypointCutMethod" />
    指定了调用doAccessCheck来做before拦截,其它拦截我没有指定,这里都能够指定的。


    inteceptorXml

    package test.aop;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class InteceptorXML {
    
    	public void doAccessCheck() {
    		System.out.println("before advice");
    	}
    
    	public void doWriteLog() {
    		System.out.println("after advice");
    	}
    
    	public void doWriteErrorLog() {
    		System.out.println("Exception advice");
    	}
    
    	public Object doAroundMethod(ProceedingJoinPoint pjp) throws Throwable {
    		System.out.println("enter around advice method.");
    
    		Object obj = pjp.proceed();
    
    		System.out.println("exit around advice method.");
    
    		return obj;
    	}
    }
    


    执行以上測试方法。得到的结果例如以下:




  • 相关阅读:
    vba根据部门分别汇总不同部门下的人员不同培训内容的时长总计,多条件求和
    vb 案例学习
    bat批处理如何删除本地策略里的用户权限分配中的拒绝从网络访问本机项的guest用户?
    vb,wps,excel 提取括号的数字
    vb,wps,excel 分裂
    vba,excel,网址提取名字与链接url
    母亲节到了 ,送什么礼物好,按键音乐提示,键盘测试,新手电脑
    MySql 数据表从1开始计数
    关于缓存的几点问题
    订单路由定时任务
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7150044.html
Copyright © 2011-2022 走看看