zoukankan      html  css  js  c++  java
  • Spring AOP(面向切面编程)

    什么是AOP

      AOP的全称是 Aspect-Oriented Programming,即面向切面编程(也称面向方面编程,它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。

      AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充。

      AspectJ是一个基于Java语言的AOP框架,它提供了强大的AOP功能。Spring2.0以后,Spring AOP引入了对AspectJ的支持,并允许直接使用AspectJ进行编程,而Spring自身的AOP API也尽量与AspectJ保持一致。新版本的Spring框架也建议使用AspectJ来开发AOP。
    使用AspectJ实现AOP有两种方式:一种是基于XML的声明式AspectJ,另一种是基于注解的声明式AspectJ。

    基于XML的声明式AspectJ

      基于XML的声明式 AspectJ是指通过XML文件来定义切面、切入点及通知,所有的切面、切入点和通知都必须定义在< aop: config>元素内。Spring配置文件中的< beans>元素下可以包含多个< aop: config>元素,一个<aop: config>元素中又可以包含属性和子元素,其子元素包括< aop: pointcut>、<aop: advisor>和< aop: aspect>。在配置时,这3个子元素必须按照此顺序来定义。在<aop: aspect>元素下,同样包含了属性和多个子元素,通过使用<aop: aspect>元素及其子元素就可以在XML文件中配置切面、切入点和通知。常用元素的配置代码如下所示。

    <!-- 定义切面Bean -->
    <bean id="myAspect" class="com. smm. aspectj.xmI.MyAspect />
    <aop:config>
    		<!-- 1.配置切面 -->
    		<aop:aspect id="aspect" ref="myAspect">
    			<!-- 2.配置切入点 -->
    			<aop:pointcut expression="execution(* com.ssm.aspectj.*.*(..))" id="myPointCut" />
    			<!-- 3.配置通知 -->
    				<!-- 前置通知 -->
    				<aop:before method="myBefore" pointcut-ref="myPointCut" />
    				<!--后置通知--> 
    				<aop:after-returning method="myAfterReturning" 
                               pointcut-ref="myPointCut" returning="returnVal" /> 
    				<!--环绕通知 -->
    				<aop:around method="myAround" pointcut-ref="myPointCut" />
    				<!--异常通知 -->
    				<aop:after-throwing method="myAfterThrowing" 
                                pointcut-ref="myPointCut" throwing="e" />
    				<!--最终通知 -->
    				<aop:after method="myAfter" pointcut-ref="myPointCut" />
    		</aop:aspect>
    	</aop:config>
    
    
    1. 在 Spring的配置文件中,配置切面使用的是<aop: aspect>元素,该元素会将一个已定义好的Spring Bean转换成切面Bean,所以要在配置文件中先定义一个普通的Spring Bean(如上述代码中定义的my Aspect)。定义完成后,通过< aop: aspect>元素的ref属性即可引用该Bean。
    2. 在 Spring的配置文件中,切入点是通过<aop: pointcut>元素来定义的。当< aop: pointcut>元素作为< aop: config>元素的子元素定义时,表示该切入点是全局切入点,它可被多个切面所共享;当< aop: pointcut>元素作为< aop: aspect>元素的子元素时,表示该切入点只对当前切面有效。在定义< aop:pointcut>元素时,通常会指定id和 expression两个属性
    • 在上述配置代码片段中,execution(* com. ssm.jdk..(..))就是定义的切入点表达式,该切入点表达式的意思是匹配com. ssm.jdk包中任意类的任意方法的执行。其中 execution0是表达式的主体,第1个表示的是返回类型,使用代表所有类型;com. ssm.jdk表示的是需要拦截的包名,后面第2个表示的是类名,使用代表所有的类;第3个表示的是方法名,使用表示所有方法;后面()表示方法的参数,其中的“..”表示任意参数。需要注意的是,第1个与包名之间有一个空格。
    1. 在配置代码中,分别使用<aop: aspect>的子元素配置了5种常用通知,这5个子元素不支持使用子元素,但在使用时可以指定一些属性

    2. AspectJ框架相关的JAR包
      spring- aspects-4.3.6. RELEASE. Jar:Spring为AspectJ提供的实现, Spring的包中已经提供。
      aspectjweaver-1.8.10.jar:是 AspectJ框架所提供的规范

    	package com.ssm.aspectj.xml;
    	import org.aspectj.lang.JoinPoint;
    	import org.aspectj.lang.ProceedingJoinPoint;
    	/**
    	 * 切面类,在此类中编写通知
    	 */
    	public class MyAspect {
    		//前置通知
    		public void myBefore(JoinPoint joinPoint){
    			System.out.print("前置通知:模拟执行权限检查...,");
    			System.out.print("目标类是:"+joinPoint.getTarget());
    			System.out.println(",被植入增强处理的目标方法为:"+
    	                          joinPoint.getSignature().getName());
    		}
    		//后置通知
    		public void myAfterReturning(JoinPoint joinPoint) {
    			System.out.print("后置通知:模拟记录日志...,");
    			System.out.println("被植入增强处理的目标方法为:" +
    	                           joinPoint.getSignature().getName());
    		}
    		/**
    		 * 环绕通知
    		 * ProceedingJoinPoint是JoinPoint的子接口,表示可执行目标方法
    		 * 1.必须是Object类型的返回值
    		 * 2.必须接收一个参数,类型为ProceedingJoinPoint
    		 * 3.必须throws Throwable
    		 */
    		public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
    			//开始
    			System.out.println("环绕开始:执行目标方法之前,模拟开启事务...,");
    			//执行当前目标方法
    			Object obj=proceedingJoinPoint.proceed();
    			//结束
    			System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...,");
    			return obj;
    		}
    		//异常通知
    		public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
    			System.out.println("异常通知:出错了"+e.getMessage());
    		}
    		//最终通知
    		public void myAfter(){
    			System.out.println("最终通知:模拟方法结束后释放资源...");
    		}
    	}
    
    
    	<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-4.3.xsd
    	        http://www.springframework.org/schema/aop
    	        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
    		<!-- 1 目标类 -->
    		<bean id="userDao" class="com.ssm.aspectj.UserDaoImpl" />
    		<!-- 2 切面 -->
    		<bean id="myAspect" class="com.ssm.aspectj.xml.MyAspect" />
    		<!-- 3 aop编程 -->
    		<aop:config>
    			<!-- 1.配置切面 -->
    			<aop:aspect id="aspect" ref="myAspect">
    				<!-- 2.配置切入点 -->
    				<aop:pointcut expression="execution(* com.ssm.aspectj.*.*(..))" id="myPointCut" />
    				<!-- 3.配置通知 -->
    					<!-- 前置通知 -->
    					<aop:before method="myBefore" pointcut-ref="myPointCut" />
    					<!--后置通知--> 
    					<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut"
    	                    returning="returnVal"/> 
    					<!--环绕通知 -->
    					<aop:around method="myAround" pointcut-ref="myPointCut" />
    					<!--异常通知 -->
    					<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" 
    	                     throwing="e" />
    					<!--最终通知 -->
    					<aop:after method="myAfter" pointcut-ref="myPointCut" />
    			</aop:aspect>
    		</aop:config>
    	</beans>
    
    

    基于注解的声明式 AspectJ

      基于XML的声明式AspectJ实现AOP编程虽然便捷,但是它也存在着一些缺点,那就是要在Spring文件中配置大量的代码信息。为了解决这个问题,AspectJ框架为AOP的实现提供了一套注解,用以取代 Spring配置文件中为实现AOP功能所配置的臃肿代码。

    	package com.ssm.aspectj.annotation;
    	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;
    	/**
    	 * 切面类,在此类中编写通知
    	 */
    	@Aspect
    	@Component
    	public class MyAspect {
    		//定义切入点表达式
    		@Pointcut("execution(* com.ssm.aspectj.*.*(..))")
    		//使用一个返回值为void、方法体为空的方法来命名切入点
    		public void myPointCut(){}
    		//前置通知
    		@Before("myPointCut()")
    		public void myBefore(JoinPoint joinPoint){
    			System.out.print("前置通知:模拟执行权限检查..,");
    			System.out.print("目标类是:"+joinPoint.getTarget());
    			System.out.println(",被植入增强处理的目标方法为:"+
    	             joinPoint.getSignature().getName());
    		}
    		//后置通知
    		@AfterReturning(value="myPointCut()")
    		public void myAfterReturning(JoinPoint joinPoint) {
    			System.out.print("后置通知:模拟记录日志..,");
    			System.out.println("被植入增强处理的目标方法为:" + 
    	             joinPoint.getSignature().getName());
    		}
    		/**
    		 * 环绕通知
    		 * ProceedingJoinPoint是JoinPoint的子接口,表示可执行目标方法
    		 * 1.必须是Object类型的返回值
    		 * 2.必须接收一个参数,类型为ProceedingJoinPoint
    		 * 3.必须throws Throwable
    		 */
    		@Around("myPointCut()")
    		public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
    			//开始
    			System.out.println("环绕开始:执行目标方法之前,模拟开启事务..,");
    			//执行当前目标方法
    			Object obj=proceedingJoinPoint.proceed();
    			//结束
    			System.out.println("环绕结束:执行目标方法之后,模拟关闭事务..,");
    			return obj;
    		}
    		//异常通知
    		@AfterThrowing(value="myPointCut()",throwing="e")
    		public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
    			System.out.println("异常通知:出错了"+e.getMessage());
    		}
    		//最终通知
    		@After("myPointCut()")
    		public void myAfter(){
    			System.out.println("最终通知:模拟方法结束后释放资源..");
    		}
    	}
    
    	<?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-4.3.xsd
    	        http://www.springframework.org/schema/aop
    	        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    	        http://www.springframework.org/schema/context
    	        http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    		<!-- 指定需要扫描的包,使注解生效 -->
    		<context:component-scan base-package="com.ssm" />
    		<!-- 启动基于注解的声明式AspectJ支持 -->
    		<aop:aspectj-autoproxy />
    	</beans>
    
    
  • 相关阅读:
    解决execjs 调用js 问题
    处理 get请求套字典问题
    js2py js逆向
    前端页面自适应
    newspaper抓新闻
    easygui
    pycharm 安装插件
    scrapy_代理使用
    SQLAlchemy 介绍,建表,及表的操作 (增 删 改 查)
    数据分析之pandas模块下
  • 原文地址:https://www.cnblogs.com/zq98/p/13182669.html
Copyright © 2011-2022 走看看