[Spring框架]Spring AOP基础入门总结一.

前言:
前面已经有两篇文章讲了Spring IOC/DI 以及 使用xml和注解两种方法开发的案例, 下面就来梳理一下Spring的另一核心AOP.

一, 什么是AOP

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码.

Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码.

二,AOP开发中的专业术语

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

三, 动态代理
spring AOP核心技术就是使用了Java 的动态代理技术, 这里简单的总结下JDK和CGLIB两种动态代理机制.

概念:
当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象。按照代理对象的创建时期不同,可以分为两种:
静态代理:程序员事先写好代理对象类,在程序发布前就已经存在了;
动态代理:应用程序发布后,通过动态创建代理对象。
其中动态代理又可分为:JDK/Cglib 动态代理.

3.1 JDK动态代理

此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。

代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。

JDK动态代理只能针对实现了接口的类生成代理。
代码实例:
UserService.java:

public interface UserService {
    public void save();

    public void update();

    public void delete();

    public void find();
}

UserServiceImpl.java:

 1 public class UserServiceImpl implements UserService {
 2
 3     @Override
 4     public void save() {
 5         System.out.println("保存用户...");
 6     }
 7
 8     @Override
 9     public void update() {
10         System.out.println("修改用户...");
11     }
12
13     @Override
14     public void delete() {
15         System.out.println("删除用户...");
16     }
17
18     @Override
19     public void find() {
20         System.out.println("查询用户...");
21     }
22
23 }

MyJdbProxy.java:

 1 /**
 2  * 使用JDK的动态代理实现代理机制
 3  *
 4  */
 5 public class MyJdbProxy implements InvocationHandler{
 6
 7     private UserService userService;
 8
 9     public MyJdbProxy(UserService userService){
10         this.userService = userService;
11     }
12
13     public UserService createProxy(){
14         // 生成UserSErvice的代理:
15         UserService userServiceProxy = (UserService) Proxy.newProxyInstance(
16                 userService.getClass().getClassLoader(), userService.getClass()
17                         .getInterfaces(), this);
18         return userServiceProxy;
19     }
20
21     @Override
22     public Object invoke(Object proxy, Method method, Object[] args)
23             throws Throwable {
24         // 判断是否是save方法:
25         if("save".equals(method.getName())){
26             // 增强:
27             System.out.println("权限校验===========");
28             return method.invoke(userService, args);
29         }
30         return method.invoke(userService, args);
31     }
32
33 }

SpringDemo.java 测试类:

 1 public class SpringDemo1 {
 2
 3     @Test
 4     // 没有代理的时候的调用方式
 5     public void demo1() {
 6         // 创建目标对象
 7         UserService userService = new UserServiceImpl();
 8
 9         userService.save();
10         userService.update();
11         userService.delete();
12         userService.find();
13     }
14
15     @Test
16     // 使用代理
17     public void demo2() {
18         // 创建目标对象
19         UserService userService = new UserServiceImpl();
20         UserService proxy = new MyJdbProxy(userService).createProxy();
21
22         proxy.save();
23         proxy.update();
24         proxy.delete();
25         proxy.find();
26     }
27 }


3.2 CGLIB 动态代理

CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。

如果目标对象没有实现接口,则默认会采用CGLIB代理;

如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
代码实例:
CustomerService.java:

 1 public class CustomerService {
 2     public void save(){
 3         System.out.println("保存客户...");
 4     }
 5     public void update(){
 6         System.out.println("修改客户...");
 7     }
 8     public void delete(){
 9         System.out.println("删除客户...");
10     }
11     public void find(){
12         System.out.println("查询客户...");
13     }
14 }

MyCglibProxy.java:

 1 /**
 2  * 使用Cglib产生代理
 3  *
 4  */
 5 public class MyCglibProxy implements MethodInterceptor{
 6
 7     private CustomerService customerService;
 8
 9     public MyCglibProxy(CustomerService customerService){
10         this.customerService = customerService;
11     }
12
13     public CustomerService createProxy(){
14         // 创建核心类:
15         Enhancer enhancer = new Enhancer();
16         // 设置父类:
17         enhancer.setSuperclass(customerService.getClass());
18         // 设置回调:
19         enhancer.setCallback(this);
20         // 创建代理:
21         CustomerService customerServiceProxy = (CustomerService) enhancer.create();
22         return customerServiceProxy;
23     }
24
25     @Override
26     public Object intercept(Object proxy, Method method, Object[] arg,
27             MethodProxy methodProxy) throws Throwable {
28         if("delete".equals(method.getName())){
29             Object obj = methodProxy.invokeSuper(proxy, arg);
30             System.out.println("日志记录==========");
31             return obj;
32         }
33         return methodProxy.invokeSuper(proxy, arg);
34     }
35 }

SpringDemo.java 测试类:

 1 public class SpringDemo2 {
 2
 3     @Test
 4     public void demo1(){
 5         CustomerService customerService = new CustomerService();
 6         customerService.save();
 7         customerService.update();
 8         customerService.delete();
 9         customerService.find();
10     }
11
12     @Test
13     public void demo2(){
14         CustomerService customerService = new CustomerService();
15         // 产生代理:
16         CustomerService proxy = new MyCglibProxy(customerService).createProxy();
17         proxy.save();
18         proxy.update();
19         proxy.delete();
20         proxy.find();
21     }
22 }

AOP包括切面(aspect)、通知(advice)、连接点(joinpoint),实现方式就是通过对目标对象的代理在连接点前后加入通知,完成统一的切面操作。

四, Spring的传统的AOP:基于ProxyFactoryBean的方式的代理

4.1 Spring的通知类型

前置通知 org.springframework.aop.MethodBeforeAdvice

  在目标方法执行前实施增强

后置通知 org.springframework.aop.AfterReturningAdvice

  在目标方法执行后实施增强

环绕通知 org.aopalliance.intercept.MethodInterceptor

  在目标方法执行前后实施增强

异常抛出通知 org.springframework.aop.ThrowsAdvice

  在方法抛出异常后实施增强

 

4.2 Spring的切面类型

Advisor : 代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截.(不带有切入点的切面,默认增强类中所有方法)

PointcutAdvisor : 代表具有切点的切面,可以指定拦截目标类哪些方法.(带有切入点的切面)

4.3 Spring传统AOP的快速入门

 4.3.1  不带有切入点的切面开发

  AOP开发需要引入的相关jar包:
  

ProductService.java:

 1 /**
 2  * 商品业务层接口
 3  *
 4  *
 5  */
 6 public interface ProductService {
 7     public void save();
 8
 9     public void update();
10
11     public void delete();
12
13     public void find();
14 }

ProductServiceImpl.java:

 1 /**
 2  * 商品业务层实现类
 3  *
 4  */
 5 public class ProductServiceImpl implements ProductService {
 6
 7     @Override
 8     public void save() {
 9         System.out.println("保存商品...");
10     }
11
12     @Override
13     public void update() {
14         System.out.println("修改商品...");
15     }
16
17     @Override
18     public void delete() {
19         System.out.println("删除商品...");
20     }
21
22     @Override
23     public void find() {
24         System.out.println("查询商品...");
25     }
26
27 }

MyBeforeAdvice.java:

 1 /**
 2  * 自定义的前置增强:
 3  *
 4  */
 5 public class MyBeforeAdvice implements MethodBeforeAdvice {
 6
 7     @Override
 8     public void before(Method method, Object[] args, Object target)
 9             throws Throwable {
10         System.out.println("前置增强=============");
11     }
12
13 }

SpringDemo.java 测试类:

 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext.xml")
 3 public class SpringDemo3 {
 4     @Resource(name="productServiceProxy")
 5     private ProductService productService;
 6
 7     @Test
 8     /**
 9      * 传统方式:
10      */
11     public void demo1(){
12         productService.save();
13         productService.update();
14         productService.delete();
15         productService.find();
16     }
17 }

  4.3.1  带有切入点的切面开发

OrderService.java:

 1 public class OrderService {
 2     public void save(){
 3         System.out.println("添加订单...");
 4     }
 5     public void update(){
 6         System.out.println("修改订单...");
 7     }
 8     public void delete(){
 9         System.out.println("删除订单...");
10     }
11     public void find(){
12         System.out.println("查询订单...");
13     }
14 }

MyAroundAdvice.java:

 1 /**
 2  * 定义的环绕增强:
 3  *
 4  */
 5 public class MyAroundAdvice implements MethodInterceptor{
 6
 7     @Override
 8     public Object invoke(MethodInvocation methodInvocation) throws Throwable {
 9         System.out.println("环绕前增强===============");
10         // 执行目标方法:
11         Object obj = methodInvocation.proceed();
12         System.out.println("环绕后增强===============");
13         return obj;
14     }
15
16 }

SpringDemo.java 测试类:

 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration("classpath:applicationContext.xml")
 3 public class SpringDemo4 {
 4
 5     @Resource(name="orderServiceProxy")
 6     private OrderService orderService;
 7
 8     @Test
 9     public void demo1(){
10         orderService.save();
11         orderService.update();
12         orderService.delete();
13         orderService.find();
14     }
15 }

applicationContext.xml 配置文件:

 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        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 5
 6
 7     <!-- 配置目标对象 -->
 8     <bean id="productService" class="cn.augmentum.aop.demo3.ProductServiceImpl"></bean>
 9
10     <!-- 配置前置增强 -->
11     <bean id="myBeforeAdvice" class="cn.augmentum.aop.demo3.MyBeforeAdvice"/>
12
13     <!-- 配置生成代理 -->
14     <bean id="productServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
15         <!-- ProxyFactoryBean常用可配置属性
16             target : 代理的目标对象
17             proxyInterfaces : 代理要实现的接口
18             如果多个接口可以使用以下格式赋值
19             <list>
20                 <value></value>
21                 ....
22             </list>
23             proxyTargetClass : 是否对类代理而不是接口,设置为true时,使用CGLib代理
24             interceptorNames : 需要织入目标的Advice
25             singleton : 返回代理是否为单实例,默认为单例
26             optimize : 当设置为true时,强制使用CGLib
27          -->
28          <property name="target" ref="productService"/>
29          <property name="proxyInterfaces" value="cn.augmentum.aop.demo3.ProductService"/>
30          <property name="interceptorNames" value="myBeforeAdvice"/>
31
32     </bean>
33
34
35     <bean id="orderService" class="cn.augmentum.aop.demo4.OrderService"/>
36
37     <bean id="myAroundAdvice" class="cn.augmentum.aop.demo4.MyAroundAdvice"/>
38
39     <bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
40         <!-- 正则表达式: . :代表任意字符    *:任意次数 -->
41         <!-- <property name="pattern" value=".*"/> -->
42         <property name="pattern" value="cn\.augmentum\.aop\.demo4\.OrderService\.save"/>
43         <property name="advice" ref="myAroundAdvice"/>
44     </bean>
45
46     <bean id="orderServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
47         <property name="target" ref="orderService"/>
48         <property name="proxyTargetClass" value="true"/>
49         <property name="interceptorNames" value="advisor"/>
50     </bean>
51
52 </beans>

基于Spring FactoryBean代理的总结:

Spring会根据类是否实现接口采用不同的代理方式:

* 实现接口:JDK动态代理.

* 没有实现接口:CGLIB生成代理.

基于ProxyFactoryBean的方式生成代理的过程中不是特别理想:

* 配置繁琐,不利为维护.

* 需要为每个需要增强的类都配置一个ProxyFactoryBean.

 

五, Spring的传统的AOP:基于自动代理

5.1 自动代理和基于ProxyFactoryBean代理方式比较:

自动代理基于BeanPostProcessor(前一篇文章讲过的工厂钩子)完成的代理.

* 在类的生成过程中就已经是代理对象.

基于ProxyFactoryBean方式代理:

* 先有目标对象,根据目标对象产生代理.

5.2自动代理的方式:
BeanNameAutoProxyCreator:基于Bean名称的自动代理

 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        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 5
 6     <!-- 配置目标对象 -->
 7     <bean id="productService" class="cn.augmentum.aop.demo3.ProductServiceImpl"></bean>
 8     <bean id="orderService" class="cn.augmentum.aop.demo4.OrderService"/>
 9
10     <!-- 配置前置增强 -->
11     <bean id="myBeforeAdvice" class="cn.augmentum.aop.demo3.MyBeforeAdvice"/>
12     <bean id="myAroundAdvice" class="cn.augmentum.aop.demo4.MyAroundAdvice"/>
13
14     <!-- 基于Bean名称的自动代理 -->
15     <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
16         <property name="beanNames" value="*Service"/>
17         <property name="interceptorNames" value="myBeforeAdvice"/>
18     </bean>
19 </beans>

 

DefaultAdvisorAutoProxyCreator:基于切面信息的自动代理

 1 <beans xmlns="http://www.springframework.org/schema/beans"
 2        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 4
 5     <!-- 配置目标对象 -->
 6     <bean id="productService" class="cn.augmentum.aop.demo3.ProductServiceImpl"></bean>
 7     <bean id="orderService" class="cn.augmentum.aop.demo4.OrderService"/>
 8
 9     <!-- 配置前置增强 -->
10     <bean id="myBeforeAdvice" class="cn.augmentum.aop.demo3.MyBeforeAdvice"/>
11     <bean id="myAroundAdvice" class="cn.augmentum.aop.demo4.MyAroundAdvice"/>
12
13     <!-- 配置切面信息 -->
14     <bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
15         <property name="advice" ref="myAroundAdvice"/>
16         <!-- <property name="pattern" value="cn\.augmentum\.aop\.demo4\.OrderService\.save"/> -->
17         <property name="patterns" value="cn\.itcast\.aop\.demo4\.OrderService\.save,cn\.augmentum\.aop\.demo3\.ProductService\.update"/>
18     </bean>
19
20     <!-- 配置基于切面信息自动代理 -->
21     <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
22 </beans>

Spring AOP最基础的知识大概就是这些了, 由于篇幅的限制及阅读的观感, 所以打算再写个Spring AOP基础入门二 来总结下 Spring基于AspectJ的AOP的开发, 这个地方才是重点, 当然这一篇博文的知识也是有利于大家对Spring AOP有了一个整体的认识了. 文章内容皆是自己学习工作整理所得, 如若有问题 欢迎指正.

 

 

时间: 2024-08-25 20:53:36

[Spring框架]Spring AOP基础入门总结一.的相关文章

[Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.

前言: 在上一篇中: [Spring框架]Spring AOP基础入门总结一. 中 我们已经知道了一个Spring AOP程序是如何开发的, 在这里呢我们将基于AspectJ来进行AOP 的总结和学习. 一, AspectJ的概述: AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件. Spring为了简化自身的AOP的开发,将AspectJ拿过来作为Spring自身一个AOP的开发.

Spring框架的一些基础知识

Spring 框架 Spring 框架是一个分层架构,由 7 个定义良好的模块组成.Spring 模块构建在核心容器之上,核心容器定义了创建.配置和管理 bean 的方式,如图 1 所示. 图 1. Spring 框架的 7 个模块 组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现.每个模块的功能如下: 核心容器:核心容器提供 Spring 框架的基本功能.核心容器的主要组件是 BeanFactory,它是工厂模式的实现.BeanFactory 使用控

跟着刚哥学习Spring框架--Spring容器(二)

Spring容器 启动Spring容器(实例化容器) -- IOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化(加载启动),这样才可以从容器中获取Bean的实例并使用.  Bean是Spring管理的基本单位,任何的Java对象和组件都被当成Bean处理,容器还负责管理Bean与Bean之间的依赖关系.  两种类型的启动实现   1.BeanFactory:IOC容器的基本实现,是Spring框架的基础设施,面向Spring本身: -- Spring容器最基本的接口就是BeanF

Spring框架--Spring依赖注入(DI)的方式

Spring框架--Spring依赖注入(DI)的方式 构造方法式: 这是我在实体类中写的一个有参构造 配置applicationContext.xml文件,由于是注入构造方法中属性的值,所以要用constructor-arg标签 name属性:构造方法中的参数名称 value属性:给属性赋值 set方法: 注入属性时要用property标签 调用: Spring集合属性的注入 调用:   原文地址:https://www.cnblogs.com/javaisbest/p/12051897.ht

[Spring框架]Spring JDBCTmplate基础入门总结.

前言:前面有讲过 Spring IOC以及AOP的基本使用方法, 这里就再来讲下Spring JDBCTemplate的使用方法. 一, 概述这里先说一下Spring 整合的一些模板: 从上图中可以看出 Spring为各种支持的持久化技术,都提供了简单操作的模板和回调. 二, 使用JdbcTemplate 2.1 Spring JDBC是Spring提供的持久层技术简化JDBC API开发,使用上和Apache公司的DBUtils框架非常类似 具体开发使用的jar包结构如图:    | 2.2,

Spring框架及AOP

Spring核心概念 Spring框架大约由20个功能模块组成,这些模块主分为六个部分: Core Container :基础部分,提供了IoC特性. Data Access/Integration Web AOP(Aspect Orient Programming) Instrumentation Test Spring两大核心技术 控制反转(Inversion of Control IoC) 称之为”依赖注入”,是面向对象编程中的一个设计理念,用来降低程序代码之间的耦合度. 将组建对象的控制

java架构解密——Spring框架的AOP

一直以来,我们应用了不少的AOP框架,但是对于AOP的底层实现却没有过多的深入,古话就是"知其然,不知其所以然",随着AOP学术讨论的骤然兴起,我也开拓了自己的眼界,深入了解了AOP这个五彩斑斓的世界! 先来看看大众的定义: 百度百科: 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函

JavaWeb_(Spring框架)Spring中IoC与DI概念入门

Spring是于2003 年兴起的一个轻量级的Java 开源框架,它由Rod Johnson创建.传统J2EE应用的开发效率低,Spring作为开源的中间件,提供J2EE应用的各层的解决方案,Spring贯穿了表现层.业务层及持久层,而不是仅仅专注于某一层的方案.可以说Spring是企业应用开发的“一站式(full-stack)”选择.然而,Spring并不想取代那些已有的框架,而是与它们无缝地整合. 简单来说,Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架. Spri

Spring框架之-AOP

在工作以及面试当中Spring是必不可少的,当然了简单的认知是spring的两大特性: IOC控制翻转(也是依赖注入).AOP(面向切面) 首先什么叫aop,aop到底能做什么?大致意思是这样的 AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理.日志管理.权限控制等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性. 例如我刚才所做的日志切面,记录每次的请求和响应消息入库 我并没有像某些人把插入库的方法写在每个请求的方法里,就像上