spring框架(三)——Spring的核心之AOP



上一节我们了解到spring的一个核心之IOC控制反转(依赖注入),那么 我们接着聊一聊spring的另外一个核心aop(面向切面编程)

1、AOP概念及原理

1.1、什么是AOP

OOP:Object Oriented Programming面向对象编程
AOP:Aspect Oriented Programming面向切面编程

我想直接说可能不懂。我们就从图片中读取信息吧。啥也不说,上图:


AOP:面向切面编程.AOP的出现不是替换OOP.解决OOP开发中一些问题.是OOP一个延伸一个扩展.
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)

AOP的底层原理  底层原理实质就是代理机制.

1.2、代理

充分理解:间接
主要作用:拦截被代理对象执行的方法,同时对方法进行增强。
1.2.1、静态代理
特点:代理类是一个真实存在的类。装饰者模式就是静态代理的一种体现形式。
1.2.2、动态代理
特点:字节码是随用随创建,随用随加载。是在运行期间生成的一个类。
a、基于接口的动态代理
提供者:JDK官方的Proxy类。
要求:被代理类必须实现一个或多个接口。
b、基于子类的动态代理
提供者:第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar。
要求:被代理类必须是一个子类(不能用final修饰的(最终类),其余类都没问题,因为都是Object的子类)。
注意:在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

Spring的AOP的底层采用两种代理机制:

  • JDK的动态代理:   只能对实现了接口的类生成代理.
  • CGLIB的动态代理:   可以对没有实现接口的类生成代理.(采用的是比较底层的字节码技术,对类生成一个子类对象.)

1.3、代理的总结:

Spring在运行期,生成动态代理对象,不需要特殊的编译器
Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术 为目标Bean执行横向织入
1.若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
2.若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
程序中应优先对接口创建代理,便于程序解耦维护
标记为final的方法,不能被代理,因为无法进行覆盖
JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
CGLib 是针对目标类生产子类,因此类或方法 不能使final的
Spring只支持方法连接点,不提供属性连接

2、Spring中的AOP

2.1、基本概念(AOP的术语)

  1. Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
  2. Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
  3. Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
  4. Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
  5. Target(目标对象):代理的目标对象
  6. Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程. spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入
  7. Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
  8. Aspect(切面): 是切入点和通知(引介)的结合

2.2、具体配置

2.2.1、Spring中的AOP
a、开发阶段(我们做的)
  1. 编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。
  2. 把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP编程人员来做。
  3. 在配置文件中,声明切入点与通知间的关系,即切面。:AOP编程人员来做。
b、运行阶段(Spring框架完成的)
Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

3 基于XML的配置(spring的xml开发)

3.1 AOP的基本配置

a、导入AOP相关的jar包(Spring的AOP是基于IoC的,所以IoC的jar也必须存在)AOP有关的jar包:4个


b、引入aop名称空间


c 编写核心业务代码必须交给spring容器


d 编写一个切面类:(某一个通知类型)也必须交给spring管理


上图的logger类是后期做的。现在是用下面的,bean的配置一样不变

  1. package springAop.aop;  
  2. public class Logger {  
  3.     //打印日志的公共方法  
  4.     //计划让其在业务核心代码(切入点方法)之前执行。 前置通知  
  5.     public void printLog(){  
  6.         System.out.println("Logger中的printLog方法开始输出日志了。。。。。");  
  7.     }  
  8. }  
package springAop.aop;
public class Logger {
	//打印日志的公共方法
	//计划让其在业务核心代码(切入点方法)之前执行。 前置通知
	public void printLog(){
		System.out.println("Logger中的printLog方法开始输出日志了。。。。。");
	}
}

注意:通知类型稍后做详解

e 配置切面


注意:切入点表达式以及切入点的配置方式稍后做详解

f 测试:编写测试代码并测试

  1. package springAop.test;  
  2.   
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  4.   
  5. import springAop.user.UserService;  
  6. public class Client {  
  7.   
  8.     public static void main(String[] args) {  
  9.         //Spring容器的初始化  
  10.         ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("springAop/bean.xml");  
  11.         //获取资源  
  12. //      UserServiceImpl userService = (UserServiceImpl) ac.getBean("userServiceImpl");  
  13.         UserService userService = (UserService)ac.getBean("userServiceImpl");  
  14.         userService.save();  
  15.     }  
  16. }  
package springAop.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import springAop.user.UserService;
public class Client {

	public static void main(String[] args) {
		//Spring容器的初始化
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("springAop/bean.xml");
		//获取资源
//		UserServiceImpl userService = (UserServiceImpl) ac.getBean("userServiceImpl");
		UserService userService = (UserService)ac.getBean("userServiceImpl");
		userService.save();
	}
}
测试的时候我获取ac.getBean的对象转换为它的接口类型,使用它实际类型抛错,不知道为什么?

结果:

  1. Logger中的printLog方法开始输出日志了。。。。。  
  2. UserServiceImpl的save方法执行了。。。  
Logger中的printLog方法开始输出日志了。。。。。
UserServiceImpl的save方法执行了。。。
注意:到这里一个简单的基于xml的spring的AOP就配置完毕!其它的东西全部都是完善!

4 详解切入点表达式(优化上面的e步骤,配置切面)

execution:匹配方法的执行(常用) execution(public * *(..))
基本语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
  • within:匹配包或子包中的方法(了解) within(springAop.aop..*)
  • this:匹配实现接口的代理对象中的方法(了解) this(springAop.aop.user.UserDAO)
  • target:匹配实现接口的目标对象中的方法(了解) target(springAop.aop.user.UserDAO)
  • args:匹配参数格式符合标准的方法(了解) args(int,int)
Spring支持使用如下三个逻辑运算符来组合切入点表达式:
  • &&:要求连接点同时匹配两个切点表达式
  • ||:要求连接点匹配至少一个切入点表达式
  • !:要求连接点不匹配指定的切入点表达式
例子:

方式一:

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.                 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  7.                 http://www.springframework.org/schema/aop  
  8.                 http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">  
  9.                   
  10.     <!-- 1 核心业务代码:service层等一系列 -->  
  11.     <bean id="userServiceImpl" class="springAop.user.impl.UserServiceImpl"></bean>  
  12.     <!-- 2 切面类:某一个通知类型的类 -->  
  13.     <bean id="loggerAdvice" class="springAop.aop.Logger"></bean>  
  14.       
  15.     <aop:config>  
  16.         <aop:aspect ref="loggerAdvice" >  
  17.           
  18.         <!--表达式全匹配 <aop:before method="printLog" pointcut="execution(public void springAop.user.impl.UserServiceImpl.save())"/> -->  
  19.         <!--访问修饰符是可以省略的<aop:before method="printLog" pointcut="execution(void springAop.user.impl.UserServiceImpl.save()"/> -->  
  20.         <!--使用*来替换返回值类型,表明可以是任意返回值<aop:before method="printLog" pointcut="execution(* springAop.user.impl.UserServiceImpl.save())"/> -->  
  21.         <!--使用*来通配方法名称。可以直接使用*,也可以使用*+部分方法名称<aop:before method="printLog" pointcut="execution(* springAop.user.impl.UserServiceImpl.*User())"/> -->  
  22.         <!--使用*来替换包名,表明包的名称可以是任意名称<aop:before method="printLog" pointcut="execution(* springAop.*.*.UserServiceImpl.*())"/> -->  
  23.         <!--使用..来替换包名,..表明的是在当前包及其子包中 <aop:before method="printLog" pointcut="execution(* springAop.user..UserServiceImpl.*())"/> -->  
  24.         <!--使用*通配类的名称。 <aop:before method="printLog" pointcut="execution(* springAop.user..*.*())"/>  -->  
  25.         <!--使用明确数据类型的参数。基本数据类型直接写:int,float等。引用类型:String可以直接写,也可以使用java.lang.String <aop:before method="printLog" pointcut="execution(* springAop.user..*.*(int))"/>  -->  
  26.         <!--使用*通配任意类型的参数。要求是必须有一个参数 <aop:before method="printLog" pointcut="execution(* springAop.user..*.*(*))"/>  -->  
  27.         <!--使用..表明有无参数都可以 <aop:before method="printLog" pointcut="execution(* springAop.user..*.*(..))"/>  -->  
  28.      
  29.             <aop:before method="printLog" pointcut="execution(* springAop.*.*.UserServiceImpl.*())"/>  
  30.         </aop:aspect>  
  31.     </aop:config>  
  32.   
  33. </beans>  
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       			http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       			http://www.springframework.org/schema/aop
   				http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
   				
   	<!-- 1 核心业务代码:service层等一系列 -->
   	<bean id="userServiceImpl" class="springAop.user.impl.UserServiceImpl"></bean>
   	<!-- 2 切面类:某一个通知类型的类 -->
   	<bean id="loggerAdvice" class="springAop.aop.Logger"></bean>
   	
   	<aop:config>
   		<aop:aspect ref="loggerAdvice" >
   		
   		<!--表达式全匹配 <aop:before method="printLog" pointcut="execution(public void springAop.user.impl.UserServiceImpl.save())"/> -->
   		<!--访问修饰符是可以省略的<aop:before method="printLog" pointcut="execution(void springAop.user.impl.UserServiceImpl.save()"/> -->
   		<!--使用*来替换返回值类型,表明可以是任意返回值<aop:before method="printLog" pointcut="execution(* springAop.user.impl.UserServiceImpl.save())"/> -->
   		<!--使用*来通配方法名称。可以直接使用*,也可以使用*+部分方法名称<aop:before method="printLog" pointcut="execution(* springAop.user.impl.UserServiceImpl.*User())"/> -->
   		<!--使用*来替换包名,表明包的名称可以是任意名称<aop:before method="printLog" pointcut="execution(* springAop.*.*.UserServiceImpl.*())"/> -->
   		<!--使用..来替换包名,..表明的是在当前包及其子包中 <aop:before method="printLog" pointcut="execution(* springAop.user..UserServiceImpl.*())"/> -->
   		<!--使用*通配类的名称。 <aop:before method="printLog" pointcut="execution(* springAop.user..*.*())"/>  -->
   		<!--使用明确数据类型的参数。基本数据类型直接写:int,float等。引用类型:String可以直接写,也可以使用java.lang.String <aop:before method="printLog" pointcut="execution(* springAop.user..*.*(int))"/>  -->
   		<!--使用*通配任意类型的参数。要求是必须有一个参数 <aop:before method="printLog" pointcut="execution(* springAop.user..*.*(*))"/>  -->
   		<!--使用..表明有无参数都可以 <aop:before method="printLog" pointcut="execution(* springAop.user..*.*(..))"/>  -->
   
   			<aop:before method="printLog" pointcut="execution(* springAop.*.*.UserServiceImpl.*())"/>
   		</aop:aspect>
   	</aop:config>

</beans>
注意:方式一的所有配置中都有一个共同缺点,不能复用
方式二:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.                 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  7.                 http://www.springframework.org/schema/aop  
  8.                 http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">  
  9.                   
  10.     <!-- 1 核心业务代码:service层等一系列 -->  
  11.     <bean id="userServiceImpl" class="springAop.user.impl.UserServiceImpl"></bean>  
  12.     <!-- 2 切面类:某一个通知类型的类 -->  
  13.     <bean id="loggerAdvice" class="springAop.aop.Logger"></bean>  
  14.       
  15.     <aop:config>  
  16.         <aop:aspect ref="loggerAdvice" >  
  17.             <!-- 使用 配置切入点的方式,实现复用  
  18.                 aop:pointcut 用于配置切入点,expression是切入点表达式,原来在pointcut属性中怎么写在这还怎么写  
  19.                 使用aop:before(或者其它通知)引入切点id  
  20.             -->  
  21.             <aop:pointcut expression="execution(* *..*.*(..))" id="pt1"/>  
  22.             <aop:before method="printLog" pointcut-ref="pt1" />  
  23.         </aop:aspect>  
  24.     </aop:config>  
  25. </beans>  
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       			http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       			http://www.springframework.org/schema/aop
   				http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
   				
   	<!-- 1 核心业务代码:service层等一系列 -->
   	<bean id="userServiceImpl" class="springAop.user.impl.UserServiceImpl"></bean>
   	<!-- 2 切面类:某一个通知类型的类 -->
   	<bean id="loggerAdvice" class="springAop.aop.Logger"></bean>
   	
   	<aop:config>
   		<aop:aspect ref="loggerAdvice" >
   			<!-- 使用 配置切入点的方式,实现复用
   				aop:pointcut 用于配置切入点,expression是切入点表达式,原来在pointcut属性中怎么写在这还怎么写
   				使用aop:before(或者其它通知)引入切点id
   			-->
     		<aop:pointcut expression="execution(* *..*.*(..))" id="pt1"/>
   			<aop:before method="printLog" pointcut-ref="pt1" />
   		</aop:aspect>
   	</aop:config>
</beans>
方式二只是将切入点单独提取出来,然后在通知时引入配置切入点的id。但只是提高了一定通用性,只能当前的切面使用。
方式三:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.                 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  7.                 http://www.springframework.org/schema/aop  
  8.                 http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">  
  9.                   
  10.     <!-- 1 核心业务代码:service层等一系列 -->  
  11.     <bean id="userServiceImpl" class="springAop.user.impl.UserServiceImpl"></bean>  
  12.     <!-- 2 切面类:某一个通知类型的类 -->  
  13.     <bean id="loggerAdvice" class="springAop.aop.Logger"></bean>  
  14.       
  15.     <aop:config>  
  16.         <!-- 把切入点声明在外面,使切入点成为全局的,这样其它的切面也可以使用 -->  
  17.         <aop:pointcut expression="execution(* *..*.*(..))" id="pt1"/>  
  18.         <aop:aspect ref="loggerAdvice" >  
  19.             <aop:before method="printLog" pointcut-ref="pt1" />  
  20.         </aop:aspect>  
  21.     </aop:config>  
  22. </beans>  
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       			http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       			http://www.springframework.org/schema/aop
   				http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
   				
   	<!-- 1 核心业务代码:service层等一系列 -->
   	<bean id="userServiceImpl" class="springAop.user.impl.UserServiceImpl"></bean>
   	<!-- 2 切面类:某一个通知类型的类 -->
   	<bean id="loggerAdvice" class="springAop.aop.Logger"></bean>
   	
   	<aop:config>
 		<!-- 把切入点声明在外面,使切入点成为全局的,这样其它的切面也可以使用 -->
   		<aop:pointcut expression="execution(* *..*.*(..))" id="pt1"/>
   		<aop:aspect ref="loggerAdvice" >
   			<aop:before method="printLog" pointcut-ref="pt1" />
   		</aop:aspect>
   	</aop:config>
</beans>

方式三只是将切入点表达式提到全局位置中。这样大家都可以引用到了。

OK、切入点表达式、和如何引用。讲完了。

5 通知类型

通知类型有5个如下:

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.                 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  7.                 http://www.springframework.org/schema/aop  
  8.                 http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">  
  9.                   
  10.     <!-- 1 核心业务代码:service层等一系列 -->  
  11.     <bean id="userServiceImpl" class="springAop.user.impl.UserServiceImpl"></bean>  
  12.     <!-- 2 切面类:某一个通知类型的类 -->  
  13.     <bean id="loggerAdvice" class="springAop.aop.Logger"></bean>  
  14.       
  15.     <aop:config>  
  16.         <!-- 把切入点声明在外面,使切入点成为全局的,这样其它的切面也可以使用 -->  
  17.         <aop:pointcut expression="execution(* *..*.*(..))" id="pt1"/>  
  18.         <aop:aspect ref="loggerAdvice" >  
  19.             <!-- 配置前置通知 :before是前置通知。永远在切入点方法(核心业务方法)执行之前执行。-->  
  20.             <!-- <aop:before method="printLog" pointcut-ref="pt1" /> -->  
  21.             <!-- 配置后置通知:after-retruning。当正常执行完成切入点方法之后执行。 如果切入点方法出现了异常则不会执行 -->  
  22.             <!-- <aop:after-returning method="printLog" pointcut-ref="pt1" /> -->  
  23.             <!-- 配置异常通知:after-throwing。当切入点方法出现异常时执行。如果切入点方法正常执行没有异常的话,则不会执行。-->  
  24.             <!--  <aop:after-throwing method="printLog" pointcut-ref="pt1" /> -->  
  25.             <!-- 配置最终通知 :after。无论切入点方法执行成功与否,最终通知都会执行。-->  
  26.             <!-- <aop:after mmethod="printLog" pointcut-ref="pt1" /> -->  
  27.             <!-- 配置环绕通知:配置环绕通知时,并没有调用核心业务方法(切入点方法)。-->  
  28.             <aop:around method="printLog" pointcut-ref="pt1"/>  
  29.         </aop:aspect>  
  30.     </aop:config>  
  31. </beans>  
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       			http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       			http://www.springframework.org/schema/aop
   				http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
   				
   	<!-- 1 核心业务代码:service层等一系列 -->
   	<bean id="userServiceImpl" class="springAop.user.impl.UserServiceImpl"></bean>
   	<!-- 2 切面类:某一个通知类型的类 -->
   	<bean id="loggerAdvice" class="springAop.aop.Logger"></bean>
   	
   	<aop:config>
 		<!-- 把切入点声明在外面,使切入点成为全局的,这样其它的切面也可以使用 -->
   		<aop:pointcut expression="execution(* *..*.*(..))" id="pt1"/>
   		<aop:aspect ref="loggerAdvice" >
   			<!-- 配置前置通知 :before是前置通知。永远在切入点方法(核心业务方法)执行之前执行。-->
   			<!-- <aop:before method="printLog" pointcut-ref="pt1" /> -->
   			<!-- 配置后置通知:after-retruning。当正常执行完成切入点方法之后执行。 如果切入点方法出现了异常则不会执行 -->
   			<!-- <aop:after-returning method="printLog" pointcut-ref="pt1" /> -->
     		<!-- 配置异常通知:after-throwing。当切入点方法出现异常时执行。如果切入点方法正常执行没有异常的话,则不会执行。-->
     		<!--  <aop:after-throwing method="printLog" pointcut-ref="pt1" /> -->
     		<!-- 配置最终通知 :after。无论切入点方法执行成功与否,最终通知都会执行。-->
     		<!-- <aop:after mmethod="printLog" pointcut-ref="pt1" /> -->
     		<!-- 配置环绕通知:配置环绕通知时,并没有调用核心业务方法(切入点方法)。-->
     		<aop:around method="printLog" pointcut-ref="pt1"/>
   		</aop:aspect>
   	</aop:config>
</beans>

6 基于注解的配置

1 使用Spring注解进行AOP配置的前提
a、资源交给Spring管理(核心业务对象,通知对象均在类中添加注解)在此之前要开启扫描包


注意:代码中请使用@Compoment注解。

b、AOP有关的注解配置
开启Spring对@AspectJ注解的支持

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xmlns:context="http://www.springframework.org/schema/context"  
  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  7.                 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  8.                 http://www.springframework.org/schema/aop  
  9.                 http://www.springframework.org/schema/aop/spring-aop-4.2.xsd   
  10.                 http://www.springframework.org/schema/context   
  11.                 http://www.springframework.org/schema/context/spring-context-3.2.xsd">  
  12.                   
  13.    <!-- 指定Spring要扫描的包(同ioc注解一样)  
  14.             注意:它会扫描当前包和当前包的子包下的所有类(base-package:以点分割包名)  
  15.        -->  
  16.         <context:component-scan base-package="springAop"></context:component-scan>  
  17.       
  18.     <!-- 开启spring对 @Aspectj注解的支持-->  
  19.     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>  
  20. </beans>  
<?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.2.xsd
       			http://www.springframework.org/schema/aop
   				http://www.springframework.org/schema/aop/spring-aop-4.2.xsd 
   				http://www.springframework.org/schema/context 
   				http://www.springframework.org/schema/context/spring-context-3.2.xsd">
   				
   <!-- 指定Spring要扫描的包(同ioc注解一样)
      		注意:它会扫描当前包和当前包的子包下的所有类(base-package:以点分割包名)
       -->
		<context:component-scan base-package="springAop"></context:component-scan>
	
	<!-- 开启spring对 @Aspectj注解的支持-->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
c、常用的AOP注解
@Aspect 配置切面

@Before:前置通知
@AfterReturning:后置通知
@AfterThrowing:异常通知
@After:最终通知
@Around:环绕通知

d、配置一个前置通知的例子

第一步:编写通知类:并交给spring管理,并配置切面,并指定通知类型

  1. package springAop.aop;  
  2.   
  3. import org.aspectj.lang.annotation.Aspect;  
  4. import org.aspectj.lang.annotation.Before;  
  5. import org.springframework.stereotype.Component;  
  6.   
  7. /** 
  8.  * 注解spring开发 
  9.  * @author mch 
  10.  * 
  11.  */  
  12. @Component  //交给spring管理--扫描包的时候就会扫描  
  13. @Aspect     //配置切面  
  14. public class Logger {  
  15.   
  16.     //打印日志的公共方法  
  17.     //计划让其在业务核心代码(切入点方法)之前执行。 前置通知  
  18.     @Before("execution(* springAop.user.impl.UserServiceImpl.save())")  
  19.     public void printLog(){  
  20.         System.out.println("Logger中的printLog方法开始输出日志了。。。。。");  
  21.     }  
  22. }  
package springAop.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * 注解spring开发
 * @author mch
 *
 */
@Component  //交给spring管理--扫描包的时候就会扫描
@Aspect     //配置切面
public class Logger {

	//打印日志的公共方法
	//计划让其在业务核心代码(切入点方法)之前执行。 前置通知
	@Before("execution(* springAop.user.impl.UserServiceImpl.save())")
	public void printLog(){
		System.out.println("Logger中的printLog方法开始输出日志了。。。。。");
	}
}
第二步:编写核心业务类,并交给spring管理
  1. package springAop.user.impl;  
  2.   
  3. import org.springframework.stereotype.Component;  
  4.   
  5. /** 
  6.  * 注解spring的核心业务类 
  7.  * @author mch 
  8.  * 
  9.  */  
  10. @Component  //交给spring来管理  
  11. public class UserServiceImpl {    
  12.     public void save(){  
  13.         System.out.println("UserServiceImpl的save方法执行了。。。");  
  14.     }  
  15.     public void update() {  
  16.         System.out.println("UserServiceImpl的update方法执行了。。。");  
  17.     }  
  18. }  
package springAop.user.impl;

import org.springframework.stereotype.Component;

/**
 * 注解spring的核心业务类
 * @author mch
 *
 */
@Component  //交给spring来管理
public class UserServiceImpl {	
	public void save(){
		System.out.println("UserServiceImpl的save方法执行了。。。");
	}
	public void update() {
		System.out.println("UserServiceImpl的update方法执行了。。。");
	}
}
第三步:前提准备的a b 和c

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:aop="http://www.springframework.org/schema/aop"  
  5.        xmlns:context="http://www.springframework.org/schema/context"  
  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  7.                 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  8.                 http://www.springframework.org/schema/aop  
  9.                 http://www.springframework.org/schema/aop/spring-aop-4.2.xsd   
  10.                 http://www.springframework.org/schema/context   
  11.                 http://www.springframework.org/schema/context/spring-context-3.2.xsd">  
  12.                   
  13.    <!-- 指定Spring要扫描的包(同ioc注解一样)  
  14.             注意:它会扫描当前包和当前包的子包下的所有类(base-package:以点分割包名)  
  15.        -->  
  16.         <context:component-scan base-package="springAop"></context:component-scan>  
  17.       
  18.     <!-- 开启spring对 @Aspectj注解的支持-->  
  19.     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>  
  20. </beans>  
<?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.2.xsd
       			http://www.springframework.org/schema/aop
   				http://www.springframework.org/schema/aop/spring-aop-4.2.xsd 
   				http://www.springframework.org/schema/context 
   				http://www.springframework.org/schema/context/spring-context-3.2.xsd">
   				
   <!-- 指定Spring要扫描的包(同ioc注解一样)
      		注意:它会扫描当前包和当前包的子包下的所有类(base-package:以点分割包名)
       -->
		<context:component-scan base-package="springAop"></context:component-scan>
	
	<!-- 开启spring对 @Aspectj注解的支持-->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
第4步:编写测试类、运行查看结果
  1. package springAop.test;  
  2.   
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  4.   
  5. import springAop.user.UserService;  
  6. import springAop.user.impl.UserServiceImpl;  
  7. public class Client {  
  8.   
  9.     public static void main(String[] args) {  
  10.         //Spring容器的初始化  
  11.         ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("springAop/bean.xml");  
  12.         //获取资源  
  13.         UserServiceImpl userService = (UserServiceImpl) ac.getBean("userServiceImpl");  
  14.         userService.save();  
  15.     }  
  16. }  
package springAop.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import springAop.user.UserService;
import springAop.user.impl.UserServiceImpl;
public class Client {

	public static void main(String[] args) {
		//Spring容器的初始化
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("springAop/bean.xml");
		//获取资源
		UserServiceImpl userService = (UserServiceImpl) ac.getBean("userServiceImpl");
		userService.save();
	}
}
运行结果:
  1. Logger中的printLog方法开始输出日志了。。。。。  
  2. UserServiceImpl的save方法执行了。。。  
Logger中的printLog方法开始输出日志了。。。。。
UserServiceImpl的save方法执行了。。。
OK、到这里基于注解的spring开发就整理完了。其它的详细内容,比如前置通知获取参数、后置通知获取返回值,异常通知获取异常信息等。等到实际项目开发用到的时候,在另行补充。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值