目录
一、Spring简介
二、Spring框架的优点有哪些?
三、IoC容器的特点
四、什么是 DI ?
五、Spring框架中的 BeanFactory 接口和 ApplicationContext 接口有什么区别?
六、Spring中Bean的实例化的三种方式
七、对 Spring 容器中 Bean 标签的理解
八、Spring 框架中属性注入有哪几种注入方式?
九、bean 的生命周期
十、bean 的作用域
十一、用注解将对象注册到Spring容器当中,有几种注解方式?它们有什么区别吗?
十二、Spring AOP 基本概念
十三、Spring AOP术语
十四、Spring 实现 AOP 的原理
Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。主要有三大特点:容器、IoC(控制反转)、AOP(面向切面编程)。同时,Spring 也是一个“一站式”框架,即 Spring 在 JavaEE 的三层架构[表现层(Web层)、业务逻辑层(Service层)、数据访问层(DAO层)]中,每一层均提供了不同的解决技术。
Spring框架主要有以下三个优点:
DI(Dependency Injection,依赖注入):需要有 IoC 环境,在 Spring 创建 Bean 对象时,动态的将依赖对象注入到 Bean 对象中去。依赖注入最大的好处就是解耦合。
一、构造方法实例化:
上面就是通过构造方法的方式实例化Bean,默认这个类是需要一个无参的构造方法。其中id和name都是Bean配置的属性,用来标识一个Bean。
二、静态工厂方法实例化:
静态工厂方法顾名思义:就是通过一个类的静态(工厂)方法来创建Bean
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
从上面的静态方法中我们就可以在对象返回之前来设置其属性,这样就完成了对象的创建。
三、实例工厂方法实例化
实例工厂方法和静态工厂方法比较相似,区别在于实例工厂方法是通过已经在容器中的Bean通过其方法实例化一个新的 Bean。
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}
当然一个实例中可以有多个实例工厂方法的,我们可以在XML中以同样的方式配置更多的Bean。
Bean 标签用来描述 Spring 容器管理的对象。
假如有一个 User 对象,需要交给 Spring 容器来管理,这样就需要在 Spring 容器的主配置文件中通过 Bean 标签来描述该对象。Bean 标签常见的属性有以下几个:
name 属性:给被管理的对象起个名称,获得对象时要根据该名称来获得;
class 属性:被管理对象的完整类名;
scope 属性:scope 属性常见的有两个属性值,singleton 和 portotype,这两个属性值用来指定创建对象时是单例还是多例,默认为 singleton(单例),但是在整合 struts2 时,ActionBean 必须配置为多例。
Spring 中属性注入的方式包括 set 方法注入、构造函数注入、p名称空间注入、spel 注入,除此之外,还包括复杂方法注入,如数组、List、Map、Properties 等属性的注入。
Bean 的生命周期包括 bean 的定义、bean 的初始化、bean 的调用和 bean 的销毁。
在配置文件中通过
bean 有5种作用域,分别是 singleton(单例,默认)、prototype(默认)、request、session、globalSession。
singleton:当一个 bean 的作用域为 singleton, 那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回 bean 的同一实例。Spring 默认选择该作用域。
prototype:prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。对所有有状态的 bean 应该使用 prototype 作用域,而对无状态的 bean 则应该使用 singleton 作用域。
request:在一次 HTTP 请求中,一个 bean 定义对应一个实例;即每次 HTTP 请求将会有各自的 bean 实例, 它们依据某个bean 定义创建而成。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效(限定 Spring MVC 中使用)。
session:在一个 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效(限定 Spring MVC 中使用)。
global session:在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。典型情况下,仅在使用 portlet context 的时候有效。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。
4种。分别是:@Component()、@Service()、@Controller()、@Respository()。
Spring 框架最早出现的只有 @Component() 注解,但如果所有的对象都使用同一个注解,很难区分对象究竟属于哪一层架构。基于此,Spring又推出了 @Service()、@Controller()、@Respository() 三种注解,用于区分对象属于哪一层架构。但4种注解方式从功能上来说没有任何区别。
AOP是 Aspect Oriented Programming 的简称,中文翻译为“面向切面编程”。可以说是 OOP(Object-Oriented Programming,面向对象编程)的补充和完善。OOP 引入封装、继承和多态等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能,日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理也是如此。这种散布在各处的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而AOP技术则恰恰相反,它利用一种称为“横切”的技术,解剖开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为“Aspect”,即方面。
所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,它们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离”。
实现AOP的技术,主要分为两大类:
和大多数技术一样,AOP已经形成了自己的术语。描述切面的常用术语有通知(advice),切点(pointcut)和连接点(joinpoint)。下图展示了这些概念是如何关联在一起的:
1、通知(Advice)
切面也是有目标的——它必须完成的工作。在AOP术语中,切面的工作被称之为通知。
通知:定义了切面是什么,何时使用,其描述了切面要完成的工作,还解决了何时执行这个工作的问题。
Spring 切面可以应用 5 种类型的通知:
2、连接点(Join Point)
连接点:是在应用执行过程中能够插入切面的一个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
3、切点(Pointcut)
切点:是缩小切面所通知的连接点的范围。如果说通知定义了切面是什么和何时的话,那么切点就定义了何处。
切点的定义会匹配通知所要织入的一个或者多个连接点。我们通常会使用明确的类和方法名称,或者利用正则表达式定义所匹配的类和方法名来指定这些切点。
4、切面(Aspect)
切面:是通知和切点的结合。通知和切点共同定义了切面的全部内容————它是什么,在何时,在何处完成其功能。
5、引入(Introduction)
引入:允许我们向现有的类添加新方法和属性。
例如:我们创建一个 Auditable 通知类,该类记录了对象最后一次修改时的状态,这很简单,只需要一个方法 setLastModified(Date) ,和一个实例变量来保存这个状态。然后,这个新方法和实例变量就可以被引入到现有的类中,从而可以在无需修改这些现有的类的情况下,让他们具有新方法的行为和状态。
6、织入(Weaving)
织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。
在目标对象的生命周期里有多个点可以进行织入:
7、目标对象(Target Object)
被一个或者多个切面所通知(Advice)的对象,也把它叫做被通知的对象(Advised)。既然SpringAOP是通过运行时代理实现的,那么这个对象永远是一个被代理(Proxied)对象。
JDK的动态代理和 cglib 代理。
JDK动态代理有缺陷,就是被代理对象必须实现接口才能产生代理对象,如果没有接口,就不能使用动态代理技术。我们用 spring 容器来实现动态代理,假如要管理的对象没有实现接口,那么就不能产生代理对象了。为了让所有的对象都能产生动态代理对象,Spring又融入了第三方代理技术cglib代理。Cglib可以对任何类生成代理对象,它的原理是对目标对象进行继承代理,如果目标对象被final修饰,那么该类无法被cglib代理。
那么Spring到底使用的是JDK代理,还是cglib代理呢?
答:混合使用。如果被代理对象实现了接口,就优先使用JDK代理,如果没有实现接口,就用用 cglib 代理。
Spring AOP的实现方式有哪些?