Java Web框架篇:Spring详解

为什么要有Spring

Web发展的几个阶段
(1)初级阶段:使用Model1(JSP+JavaBean)/Model2(Jsp+Servlet+JavaBean)/三层模型(表示层(JSP/Servlet)+业务逻辑层+持久化层)进行开发;
(2)中级阶段:使用EJB进行分布式应用开发,忍受重量级框架带来的种种麻烦;
(3)高级阶段:使用Spring春天带给我们的美好,但是还要忍受很多繁琐的配置;
(4)骨灰级阶段:使用Spring Boot,畅享“预定大于配置”带给我们的种种乐趣;

Spring概述

是什么?

一个开源的轻量级开发框架,是为了解决企业应用程序的复杂性而创建的。
Spring简介

为什么?

EJB时代,企业级应用开发困难。Spring设计初衷是使JavaEE更加容易,为JavaBean提供配置框架,使程序易于测试,设计目标是简单易用,与应用程序解耦,致力于集成其他解决方案,而不是竞争。Spring不仅仅限于服务器端的开发,从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中学习受益。

怎么做?

Spring包括Core+Context,Aop,Dao,ORM,Web(SpringMVC),JEE 等模块。
Java Web框架篇:Spring详解_第1张图片

1、IOC和DI

IOC: 控制反转
spring中有三种注入方式,一种是set注入,一种是接口注入,另一种是构造方法注入。
IOC,字面理解是控制反转,即对象的控制权被反转了(是什么)。之前一个对象中依赖另一个对象,需要自己new出来,当对象间的依赖关系非常复杂时,这个过程就变得很繁琐,并且代码间的耦合会很高。

耦合,也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息。

现在可以通过Ioc容器来管理控制对象的生成,可以把对象的实例化过程简单化,代码间解耦(为什么)。具体可以从DI(Dependency Injection) DL(Dependency Lookup)两个角度理解Ioc。DI中注入的方式包括属性,构造器,setter注入,DL含义是通过容器的API来查找所依赖的资源和协作对象,从Ioc容器维护的bean map中取出来(怎么做)

DI: Dependency Injection 依赖注入
spring这个容器中,替你管理着一系列的类,前提是你需要将这些类交给spring容器进行管理,然后在你需要的时候,不是自己去定义,而是直接向spring容器索取,当spring容器知道你的需求之后,就会去它所管理的组件中进行查找,然后直接给你所需要的组件.
实现IOC思想需要DI做支持
注入方式: 1.set方式注入 2.构造方法注入 3.字段注入
注入类型: 1.值类型注入 2.引用类型注入
好处:

1.降低组件之间的耦合度,实现软件各层之间的解耦.
2.可以使容器提供众多服务如事务管理消息服务处理等等。当我们使用容器管理事务时,开发人员就不需要手工 控制事务,也不需要处理复杂的事务传播
3.容器提供单例模式支持,开发人员不需要自己编写实现代码.
4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能
5.容器提供众多的辅佐类,使这些类可以加快应用的开发.如jdbcTemplate HibernateTemplate

applicationContext & BeanFactory区别

BeanFactory接口

(1) spring的原始接口,针对原始接口的实现类功能较为单一
(2)BeanFactory接口实现类的容器,特点是每次在获得对象时才会创建对象

ApplicationContext接口

(1)每次容器启动时就会创建容器中配置的所有对象
(2)提供了更多功能
(3)从类路径下加载配置文件: ClassPathXmlApplicationContext
从硬盘的绝对路径下加载配置文件:FileSystemXmlApplication

spring配置详解

1、元素属性

bean元素:使用该元素描述需要spring容器管理对象
name属性:给被管理的对象起个名字,获得对象时getBean(“name值”)
class属性:被管理对象的完整类名
id属性:与name属性一模一样,名称不可重复,不能使用特殊字符
name和id之间的一些注意点:

1、配置两个相同的 id 或者 name 都不能通过。
2、如果既配置了 id ,也配置了 name ,则两个都生效。如果id和name都没有指定,则用类全名作为name,如,则你可以通过getBean(“com.stamen.BeanLifeCycleImpl”)返回该实例。
3、如果配置基本类的时候,注解和配置文件都使用的时候,注解和配置文件中 name 相同的时候, 则两个冲突,配置文件生效。
如果配置基本类的时候,注解和配置文件都使用的时候,注解和配置文件中 name 不相同的时候, 则两个不冲突,都能够生效。

2、bean元素进阶( scope属性 生命周期属性)—————单例多例

1.scope属性
(1)singleton 默认值
单例对象 :被标识为单例的对象在spring容器中只会存在一个实例
(2)prototype
多例原型:被标识为多例的对象,每次在获得才会被创建,每次创建都是新的对象
(3)request
Web环境下,对象与request生命周期一致
(4)session
Web环境下,对象与session生命周期一致
总结:绝大多数情况下,使用单例singleton(默认值),但是在与struts整合时候,务必要用prototype多例,因为struts2在每次请求都会创建一个新的Action,若为单例,在多请求情况下,每个请求找找spring拿的都是同一个action。

2.生命周期属性(了解)———初始化和销毁
(1)配置一个方法作为生命周期初始化方法,spring会在对象创建之后立刻调用 init-method
(2)配置一个方法作为生命周期的销毁方法,spring容器在关闭并销毁所有容器中的对象之前调用destory-method

<bean init-method=“init”  destory-method=“destory”></bean>        对应注解为@PostConstruct

    <bean name=“hello” class=“完整类名”></bean>                                 对应注解为@PreDestory

3.模块化配置,即分模块配置(导入其他spring配置文件)

<beans>
    <import resource = “spring配置文件的全路径名” />
</beans>

3、spring三种对象的创建方式

(1)空参数构造(重要)
在这里插入图片描述
(2)静态工厂创建(调用静态方法创建)
调用UserFactory类的静态createUser方法创建名为user的对象,放入容器

<bean name="user" class="cn.itcats.UserFactory" factory-method="createUser"></bean>

(3)实例工厂创建(调用非静态方法创建)——需要配置两个bean,因为无法通过类名调用非静态方法

<bean name="user2" factory-bean="userFactory" factory-method="createUser"></bean>
 
<bean name=“userFactory” class=cn.itcats.UserFactory></bean>

spring注入方式

(1)set方式注入(重点)————值类型用value注入 引用类型用ref注入

 <!--bean的set方法注入-->
    <bean id="person" class="com.openlab.bean.Person">
    <!-- 值类型注入:为person对象中名为name属性注入jack作为值 -->
        <property name="name" value="jack"/>
        <property name="age" value="20"/>
         <!--引用需要用ref -->
         <!-- 引用类型注入:为cat属性注入下面配置的cat对象-->
        <property name="cat" ref="cat"/>

    </bean>

    <bean id="cat" class="com.openlab.bean.Cat">
        <property name="name" value="ketty" />

    </bean>

(2)构造方法注入

Java Web框架篇:Spring详解_第2张图片

(3)Bean 的p命名空间的属性注入———实际上set注入,spring特有,为了简化写法

1、applicationContext.xml中标签头部导入p命名空间
xmlns:p=“http://www.springframework.org/schema/p”

2、书写格式:值类型注入—— p:属性名=“值” 引用类型注入—— p:属性名-ref=“引用的 name属性”,
把Run类中的name属性值设置为haha,age属性设置为20,引用属性hello引用

(4)spel注入: spring Expression Language spring表达式语言

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class collectiontDI {
    private String[] arr;
    private List<String> list;
    private Map<String,String> map;
    private Set<String> set;

}

<bean class="com.openlab.bean.collectiontDI" id="collectiontDI">
        <property name="arr">
            <array>
                <value>张三丰</value>
                <value>里斯</value>
                <value>王f五i</value>
            </array>
        </property>
        <property name="list">
            <list>
            <value>数据库</value>
            <value>前端</value>
            <value>web</value>
            </list>
        </property>

    <property name="map">
        <map>
            <entry key="cn" value="China"></entry>
            <entry key="en" value="England"></entry>
            <entry key="jp" value="Jpapan"></entry>
        </map>
    </property>
        <property name="set">
            <set>
                <value>数据库</value>
                <value>前端</value>
                <value>web</value>
            </set>
        </property>
    </bean>

(6)使用注解方式代替配置文件(官方推荐使用注解)

1.在applicationContext.xml中书写指定扫描注解

在这里插入图片描述

2.在类中书写Component

Java Web框架篇:Spring详解_第3张图片

注意:假如不写括号内的值(即name或id),默认使用类名首字母小写作为搜索,比如Student类中使用了@Component 没有书写括号和值,那么默认搜索id或name为student。

3.指定对象的作用范围Scope

Java Web框架篇:Spring详解_第4张图片
声明Student类对象为多例 下面是对singleton和prototype的一些补充

singleton作用域:当把一个Bean定义设置为singleton作用域是,Spring IoC容器中只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean定义相匹配,则只会返回该Bean的同一实例。值得强调的是singleton作用域是Spring中的缺省作用域。

prototype作用域:prototype作用域的Bean会导致在每次对该Bean请求(将其注入到另一个Bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的Bean实例。根据经验,对有状态的Bean应使用prototype作用域,而对无状态的Bean则应该使用singleton作用域。对于具有prototype作用域的Bean,有一点很重要,即Spring不能对该Bean的整个生命周期负责。具有prototype作用域的Bean创建后交由调用者负责销毁对象回收资源。简单的说:

singleton 只有一个实例,也即是单例模式。
prototype访问一次创建一个实例,相当于new。

4.值类型的注入

														实际通过反射field赋值
				![在这里插入图片描述](https://img-blog.csdnimg.cn/4d01aa4f16e548aa9bcaf6d6eddc8a00.png)
														实际通过set方式赋值		
				![在这里插入图片描述](https://img-blog.csdnimg.cn/69242fcdf8804d578297e6b16b131f8f.png)

5.引用类型的注入

面试题: @AutoWired和@Resource的区别?

@AutoWired默认以类型进行查找,@Resource默认以名称进行查找
@Autowired 还有一个属性 required,默认值为 true,表示当匹配失败后,会终止程序运
行。若将其值设置为 false,则匹配失败,将被忽略,未匹配的属性值为 null。

@AutoWired(required=false) + @Qualifier(“user”) == @Resource(name=“user”)
其中@Resource注解是jdk1.6后才有的
在这里插入图片描述在这里插入图片描述
Java Web框架篇:Spring详解_第5张图片

6.spring整合junit测试(spring创建容器)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)

Java Web框架篇:Spring详解_第6张图片

更多:
最好理解的: spring ioc原理讲解,强烈推荐!
控制反转和依赖注入的理解(通俗易懂)
Spring源码剖析——核心IOC容器原理
Spring源码剖析——依赖注入实现原理

2、AOP 面向切面编程

AOP 简介

Aop就是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
利用Aop可以对业务逻辑的各部分进行隔离,从而降低各部分耦合度,提高程序的可重用性,提高开发效率
spring中面向切面变成的实现有两种方式,一种是动态代理,一种是CGLIB,动态代理必须要提供接口,而CGLIB实现是有继承,即:

接口+实现类,spring采用jdk的动态代理实现,
实现类,spring采用cglib字节码增强实现。

当然也可以通过集成AspectJ可以更方便的实现自定义切面。Spring Aop支持前/后/环绕等多种类型的通知机制:

before(前置通知):在一个方法之前执行的通知。
after(最终通知):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
after-returning(后置通知):在某连接点正常完成后执行的通知。
after-throwing(异常通知):在方法抛出异常退出时执行的通知。
around(环绕通知):在方法调用前后触发的通知。

例如,转账,在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事
务等交叉业务逻辑,而这些业务逻辑与主业务逻辑间并无直接关系。但,它们的代码量所占
比重能达到总代码量的一半甚至还多。它们的存在,不仅产生了大量的“冗余”代码,还大
大干扰了主业务逻辑—转账。
好处

  • 轻量级的容器框架,没有侵入性
  • 使用IoC容器更加容易组合对象直接间关系,面向接口编程,降低耦合
  • Aop可以更加容易的进行功能扩展,遵循ocp开发原则
  • 创建对象默认是单例的,不需要再使用单例模式进行处理
  • 基于Ioc Aop,Spring提供了事务管理,Spring Web,日志等一系列经典应用
    Java Web框架篇:Spring详解_第7张图片

AOP实践(AspectJ)-日志实现
缺点
业务功能依赖spring特有的功能,依赖与spring环境。

AOP 编程术语

(1) 切面(Aspect)
切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面
是通知(Advice)。实际就是对主业务逻辑的一种增强。
或者说切面就是切入点+通知————通知(Advice)说明了干什么的内容(即方法体代码)和什么时候干(什么时候通过方法名中的before,after,around等就能知道),然后切入点说明了在哪干(指定到底是哪个方法),切点表达式等定义。
(2) 连接点(JoinPoint)
连接点指可以被切面织入的具体方法。通常业务接口中的方法均为连接点。
(3) 切入点(Pointcut)
切入点指声明的一个或多个连接点的集合。通过切入点指定一组方法。
被标记为 final 的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不
能被增强的。
(4) 目标对象(Target)
目 标 对 象 指 将 要 被 增 强 的 对 象 。 即 包 含 主 业 务 逻 辑 的 类 的 对 象 。 上 例 中 的
StudentServiceImpl 的对象若被增强,则该类称为目标类,该类对象称为目标对象。当然,
不被增强,也就无所谓目标不目标了。
(5) 通知(Advice)
通知表示切面的执行时间,Advice 也叫增强。上例中的 MyInvocationHandler 就可以理
解为是一种通知。换个角度来说,通知定义了增强代码切入到目标代码的时间点,是目标方
法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。
切入点定义切入的位置,通知定义切入的时间。
(6) 织入(Weaving)
将通知应用到连接点形成切入点的过程

AspectJ 对 AOP 的实现

在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。
AspectJ 是一个优秀面向切面的框架,它扩展了 Java 语言,提供了强大的切面实现。
AspectJ官网地址

AspectJ 的通知类型

AspectJ 中常用的通知有五种类型:
(1)前置通知
(2)后置通知
(3)环绕通知
(4)异常通知
(5)最终通知
Java Web框架篇:Spring详解_第8张图片
配置 applicationContext.xml
Java Web框架篇:Spring详解_第9张图片

AspectJ 的切入点表达式

execution(modifiers-pattern ?  ret-type-pattern  declaring-type-pattern ? name-pattern(param-pattern)  throws-pattern?)

解释:
modifiers-pattern 访问权限类型
ret-type-pattern 返回值类型
declaring-type-pattern 包名类名
name-pattern(param-pattern) 方法名(参数类型和参数个数)
throws-pattern 抛出异常类型
?表示可选的部分
以上表达式共 4 个部分:
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution 表达式中明显就
是方法的签名。注意,表达式中未加粗文字表示可省略部分,各部分间用空格分开。在其中可
以使用以下符号:
Java Web框架篇:Spring详解_第10张图片
举例:
execution(public * *(…))
指定切入点为:任意公共方法。

execution(* set*(…))
指定切入点为:任何一个以“set”开始的方法。

execution(* com.xyz.service..(…))
指定切入点为:定义在 service 包里的任意类的任意方法。

execution(* com.xyz.service….(…))
指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“…”出现在类名中时,后面必须跟“*”,表示包、子包下的所有类。

execution(* …service..*(…))
指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点

execution(* .service..*(…))
指定只有一级包下的 serivce 子包下所有类(接口)中所有方法为切入点

execution(* .ISomeService.(…))
指定只有一级包下的 ISomeSerivce 接口中所有方法为切入点

execution(* …ISomeService.(…))
指定所有包下的 ISomeSerivce 接口中所有方法为切入点

execution(* com.xyz.service.IAccountService.*(…))
指定切入点为:IAccountService 接口中的任意方法。

execution(* com.xyz.service.IAccountService+.*(…))
指定切入点为:IAccountService 若为接口,则为接口中的任意方法及其所有实现类中的任意方法;若为类,则为该类及其子类中的任意方法。

execution(* joke(String,int)))
指定切入点为:所有的 joke(String,int)方法,且 joke()方法的第一个参数是 String,第二个参数是 int。如果方法中的参数类型是 java.lang 包下的类,可以直接使用类名,否则必须使用全限定类名,如 joke( java.util.List, int)。

execution(* joke(String,*)))
指定切入点为:所有的 joke()方法,该方法第一个参数为 String,第二个参数可以是任意类型,如joke(String s1,String s2)和joke(String s1,double d2)都是,但joke(String s1,double d2,String s3)不是。

execution(* joke(String,…)))
指定切入点为:所有的 joke()方法,该方法第一个参数为 String,后面可以有任意个参数且参数类型不限,如 joke(String s1)、joke(String s1,String s2)和 joke(String s1,double d2,String s3)都是。

execution(* joke(Object))
指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类型。joke(Object ob)是,但,joke(String s)与 joke(User u)均不是。

execution(* joke(Object+)))
指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类型或该类的子类。不仅 joke(Object ob)是,joke(String s)和 joke(User u)也是。

AspectJ 的开发环境

(1) maven 依赖

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version>
</dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.5.RELEASE</version>
</dependency>
插件
<build>
<plugins>
 <plugin>
 <artifactId>maven-compiler-plugin</artifactId>
 <version>3.1</version>
 <configuration>
 <source>1.8</source>
 <target>1.8</target>
 </configuration>
 </plugin>
</plugins> 
</build>

(2) 引入 AOP 约束
在 AspectJ 实现 AOP 时,要引入 AOP 的约束。配置文件中使用的 AOP 约束中的标签,均是 AspectJ 框架使用的,而非 Spring 框架本身在实现 AOP 时使用的。AspectJ 对于 AOP 的实现有注解和配置文件两种方式,常用是注解方式。

AspectJ 基于注解的 AOP 实现

AspectJ 提供了以注解方式对于 AOP 的实现。
(1) 实现步骤
A、Step1:定义业务接口与实现类
在这里插入图片描述Java Web框架篇:Spring详解_第11张图片
B、 Step2:定义切面类
类中定义了若干普通方法,将作为不同的通知方法,用来增强功能。
Java Web框架篇:Spring详解_第12张图片
C、 Step3:声明目标对象切面类对象
Java Web框架篇:Spring详解_第13张图片
D、Step4:注册 AspectJ 的自动代理
在定义好切面 Aspect 后,需要通知 Spring 容器,让容器生成“目标类+ 切面”的代理
对象。这个代理是由容器自动生成的。只需要在 Spring 配置文件中注册一个基于 aspectj 的
自动代理生成器,其就会自动扫描到@Aspect 注解,并按通知类型与切入点,将其织入,并
生成代理。
Java Web框架篇:Spring详解_第14张图片
aop:aspectj-autoproxy/的底层是由 AnnotationAwareAspectJAutoProxyCreator 实现的。
从其类名就可看出,是基于 AspectJ 的注解适配自动代理生成器。
其工作原理是,aop:aspectj-autoproxy/通过扫描找到@Aspect 定义的切面类,再由切
面类根据切入点找到目标类的目标方法,再由通知类型找到切入的时间点。
E、 Step5:测试类中使用目标对象的 id
Java Web框架篇:Spring详解_第15张图片

@Before 前置通知-方法有 JoinPoint 参数

在目标方法执行之前执行。被注解为前置通知的方法,可以包含一个 JoinPoint 类型参
数。该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、
目标对象等。
不光前置通知的方法,可以包含一个 JoinPoint 类型参数,所有的通知方法均可包含该
参数。
Java Web框架篇:Spring详解_第16张图片

@AfterReturning 后置通知-注解有 returning 属性

在目标方法执行之后执行。由于是目标方法之后执行,所以可以获取到目标方法的返回值。该注解的 returning 属性就是用于指定接收方法返回值的变量名的。所以,被注解为后置通知的方法,除了可以包含 JoinPoint 参数外,还可以包含用于接收返回值的变量。该变量最好为 Object 类型,因为目标方法的返回值可能是任何类型。
接口增加方法:
Java Web框架篇:Spring详解_第17张图片
实现方法:
Java Web框架篇:Spring详解_第18张图片
定义切面:
Java Web框架篇:Spring详解_第19张图片

@Around 环绕通知-增强方法有 ProceedingJoinPoint参数

在目标方法执行之前之后执行。被注解为环绕增强的方法要有返回值,Object 类型。并
且方法可以包含一个 ProceedingJoinPoint 类型的参数。接口 ProceedingJoinPoint 其有一个
proceed()方法,用于执行目标方法。若目标方法有返回值,则该方法的返回值就是目标方法
的返回值。最后,环绕增强方法将其返回值返回。该增强方法实际是拦截了目标方法的执行。
接口增加方法:
Java Web框架篇:Spring详解_第20张图片
接口方法的实现:
Java Web框架篇:Spring详解_第21张图片
定义切面:
Java Web框架篇:Spring详解_第22张图片

@AfterThrowing 异常通知-注解中有 throwing 属性

在目标方法抛出异常后执行。该注解的 throwing 属性用于指定所发生的异常类对象。
当然,被注解为异常通知的方法可以包含一个参数 Throwable,参数名称为 throwing 指定的
名称,表示发生的异常对象。
增加业务方法:
Java Web框架篇:Spring详解_第23张图片
方法实现:
Java Web框架篇:Spring详解_第24张图片
定义切面:
Java Web框架篇:Spring详解_第25张图片

@After 最终通知

无论目标方法是否抛出异常,该增强均会被执行。
增加方法:
Java Web框架篇:Spring详解_第26张图片
方法实现:
在这里插入图片描述
定义切面:
Java Web框架篇:Spring详解_第27张图片

@Pointcut 定义切入点

当较多的通知增强方法使用相同的 execution 切入点表达式时,编写、维护均较为麻烦。
AspectJ 提供了@Pointcut 注解,用于定义 execution 切入点表达式。
其用法是,将@Pointcut 注解在一个方法之上,以后所有的 execution 的 value 属性值均
可使用该方法名作为切入点。代表的就是@Pointcut 定义的切入点。这个使用@Pointcut 注解
的方法一般使用 private 的标识方法,即没有实际作用的方法。
Java Web框架篇:Spring详解_第28张图片

Spring装配Bean

生命周期流程图

Java Web框架篇:Spring详解_第29张图片Java Web框架篇:Spring详解_第30张图片

以BeanFactory为例,说明一个Bean的生命周期活动

Bean的建立, 由BeanFactory读取Bean定义文件,并生成各个实例
Setter注入,执行Bean的属性依赖注入
BeanNameAware的setBeanName(), 如果实现该接口,则执行其setBeanName方法
BeanFactoryAware的setBeanFactory(),如果实现该接口,则执行其setBeanFactory方法
BeanPostProcessor的processBeforeInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processBeforeInitialization()方法
InitializingBean的afterPropertiesSet(),如果实现了该接口,则执行其afterPropertiesSet()方法
Bean定义文件中定义init-method
BeanPostProcessors的processAfterInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processAfterInitialization()方法
DisposableBean的destroy(),在容器关闭时,如果Bean类实现了该接口,则执行它的destroy()方法
Bean定义文件中定义destroy-method,在容器关闭时,可以在Bean定义文件中使用“destory-method”定义的方法

Spring装配Bean的过程

装配bean过程

  1. 实例化;
  2. 设置属性值;
  3. 如果实现了BeanNameAware接口,调用setBeanName设置Bean的ID或者Name;
  4. 如果实现BeanFactoryAware接口,调用setBeanFactory 设置BeanFactory;
  5. 如果实现ApplicationContextAware,调用setApplicationContext设置ApplicationContext
  6. 调用BeanPostProcessor的预先初始化方法;
  7. 调用InitializingBean的afterPropertiesSet()方法;
  8. 调用定制init-method方法;
  9. 调用BeanPostProcessor的后初始化方法;

Spring容器关闭过程

调用DisposableBean的destroy();
调用定制的destroy-method方法;

其他说明

懒加载:

就是我们在spring容器启动的是先不把所有的bean都加载到spring的容器中去,而是在当需要用的时候,才把这个对象实例化到容器中。

spring配置文件中bean默认是lazy-init=“false”为非懒加载。下面具体说明。

1、默认情况下bean实例化过程:
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("/beans.xml"); //随着spring容器加载,就实例化了bean。
2、给bean设置 lazy-init=“true”
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("/beans.xml"); //随着spring容器加载,就不会实例化bean。
Person person = ctx.getBean(“person”);//这一步才在实例化bean。就是前面说的需要的时候再实例化了。

简单描述实例化bean的过程如下:
实例化bean测试结果:先构造函数——>然后是b的set方法注入—— >InitializingBean 的afterPropertiesSet方法——>init- method方法

spring管理bean的作用域

singleton作用域
如果一个 bean 的作用域被声明为 singleton,那么 Spring IOC 容器将只创建一个该对象的实例,并将其存储在缓存中。每次请求该 bean 时,都会返回该缓存对象。Singleton 作用域是所有 bean 的默认作用域。

<bean id="man" class="com.openlab.pojo.Man" scope="singleton">        
     <constructor-arg name="age" value="5"></constructor-arg>        
     <constructor-arg name="manName" value="张三"></constructor-arg>
     <constructor-arg name="userCar" value="宾利"></constructor-arg>                
  </bean>

prototype作用域
如果一个 bean 的作用域被声明为 prototype,那么每次请求该 bean 时,Spring IOC 都会返回一个新的实例。

<bean id="man" class="com.openlab.pojo.Man" scope="singleton">        
      <constructor-arg name="age" value="5"></constructor-arg>        
      <constructor-arg name="manName" value="张三"></constructor-arg>
      <constructor-arg name="userCar" value="宾利"></constructor-arg>             
</bean>

相关文章:
Spring Bean的生命周期(非常详细)
Spring Bean的生命周期
Spring学习之Bean详解

你可能感兴趣的:(JavaWeb篇,spring,java)