Spring的底层原理
之前说明的都是Spring的应用(64章博客开始(包括其后面的相关博客)),现在来说明他为什么可以那样做
在说明之前,这里需要对64章博客中的spring的了解需要再次的说明:
Spring 是分层的 full-stack(英文意思:全栈的,一般意味着各层能够无缝的集成在一起) 轻量级(复杂度比较低)开源框架,以 IoC 和 AOP 为内核,提供了展现层 Spring MVC 和业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,已经成为使用最多的 Java EE 企业应用开源框架
Spring 官方网址:http://spring.io/
我们经常说的 Spring 其实指的是Spring Framework(spring 框架)
一般spring可能对jdk有版本的限制,比如jdk8及其以上是操作spring5开始的版本,6(jdk)则是4(spring),5则是3,具体可能随着时间的推移会发生改变,最好是观察官网
Spring是一个分层⾮常清晰并且依赖关系、职责定位⾮常明确的轻量级框架,主要包括⼏个大模块:数据处理模块、Web模块、AOP(Aspect Oriented Programming)/Aspects模块、Core Container模块 和 Test 模块,如下图所示,Spring依靠这些基本模块,实现了一个令⼈愉悦的融合了现有解决方案的零 侵⼊的轻量级框架
1:Spring核心容器(Core Container) :
容器是Spring框架最核心的部分,它管理着Spring应用中bean的创建、配置和管理,在该模块中,包括了Spring bean工⼚,它为Spring提供了DI的功能,基于bean工⼚,我们还会发现有多种Spring应用上下⽂的实现,所有的Spring模块都构建于核心 容器之上
2:面向切面编程(AOP)/Aspects:
Spring对面向切面编程提供了丰富的⽀持,这个模块是Spring应用系统中开发切面的基础,与DI一样,AOP可以帮助应用对象解耦
3:数据访问与集成(Data Access/Integration):
Spring的JDBC和DAO模块封装了大量样板代码,这样可以使得数据库代码变得简洁,也可以更专 注于我们的业务,还可以避免数据库资源释放失败而引起的问题,另外,Spring AOP为数据访问 提供了事务管理服务,同时Spring还对ORM进行了集成,如Hibernate、MyBatis等,该模块由JDBC、Transactions、ORM、OXM 和 JMS 等模块组成
4:Web 该模块提供了SpringMVC框架给Web应用,还提供了多种构建和其它应用交互的远程调用方案,SpringMVC框架在Web层提升了应用的松耦合⽔平
5:Test 为了使得开发者能够很方便的进行测试,Spring提供了测试模块以致⼒于Spring应用的测试, 通过该模块,Spring为使用Servlet、JNDI等编写单元测试提供了一系列的mock对象实现
这里首先建议先复习复习64章博客的内容,对后面的源码说明或者自定义框架(部分)才会有更好的理解(虽然在对应的博客中也大致说明了我自己认为的实现原理(那个时候并没有看源码,但理解还是正确的),看看即可,现在我们来直接看看源码是如何实现的)
同样的,与上一章博客相同的是,这里还是先操作对应的自定义框架(这里是Spring),来更加的容易理解后面的源码
最后:之前说明的Spring的应用(64章博客开始)中,其实还是有很多细节并没有说明,比如循环依赖(只是说明了理论的原因),在这里都会进行说明的
现在开始操作:
实际上IOC和AOP只是一个思想而已,并非Spring存在他们才存在,而是他们首先就存在,只是Spring更好的利用他们而已
有些框架中,并没有通过配置文件将创建对象进行保存,而Spring就保存了(这样的操作就是IOC思想,Spring利用了这个),使得可以使用,IOC中我们可以利用构造的改变来解释为什么使用IOC,这是一个主要的解释,无论是直接依赖还是硬编码基本都存在这样的问题,因为类是在自身的,而不是从其他地方获取,IOC在解决硬编码(基本自带解决一点耦合,如编译期耦合)问题的同时,在Spring中还会保存
为什么叫做控制反转(IOC):
控制:指的是对象创建(实例化、管理)的权利
反转:控制权交给外部环境了(IOC容器给你类)
当然还包括DI,关系如下:
DI利用IOC进一步操作
大多数IOC(包括DI)和AOP在64章博客都有大致说明这里我们来说明没有说明过的
其中AOP是OOP的延续,那么我们具体说明一下OOP
OOP三大特征:封装、继承和多态,OOP是一种垂直继承体系
OOP编程思想可以解决大多数的代码重复问题(封装代码,这样就不用继续写对应很多的代码了),但是有一些情况是处理不了的,比如下面的在顶级⽗类al中的多个方法中相同位置出现了重复代码,OOP就解决不了
public class al {
public static void main(String[] args) {
al a = new al();
a.fa1();
a.fa2();
}
public void fa1() {
long l = System.currentTimeMillis();
System.out.println("fa1");
long l1 = System.currentTimeMillis();
System.out.println("执行时长:" + (l1 - l));
}
public void fa2() {
long l = System.currentTimeMillis();
System.out.println("fa2");
long l1 = System.currentTimeMillis();
System.out.println("执行时长:" + (l1 - l));
}
}
横切逻辑代码:
横切逻辑代码存在什么问题:
1:横切代码重复问题
2:横切逻辑代码和业务代码混杂在一起,代码臃肿,维护不方便
AOP出场,AOP独辟蹊径提出横向抽取机制,将横切逻辑代码和业务逻辑代码进行一起分析处理
代码拆分容易,那么如何在不改变原有业务逻辑的情况下,悄⽆声息的把横切逻辑代码应用到原有的业 务逻辑中,达到和原来一样的效果,这个是比较难的,这就是AOP要解决的问题
为什么叫做面向切面编程:
切:指的是横切逻辑,原有业务逻辑代码我们不能动,只能操作横切逻辑代码,所以面向横切逻辑
面:横切逻辑代码往往要影响的是很多个方法,每一个方法都如同一个点,多个点构成面,有一个 面的概念在⾥面
至此IOC和AOP要操作的问题说明完毕
⼿写实现 IoC 和 AOP:
这里参照这个图:
具体实现想象即可
问题一:在上述案例实现中,service 层实现类在使用 dao 层对象时,直接在TransferServiceImpl 中通过 AccountDao accountDao = new JdbcAccountDaoImpl() 获得了 dao层对 象,然而一个 new 关键字却将 TransferServiceImpl 和 dao 层具体的一个实现类JdbcAccountDaoImpl 耦合在了一起,如果说技术架构发生一些变动,dao 层的实现要使用其它技术, 比如 Mybatis,思考切换起来的成本,每一个 new 的地方都需要修改源代码,重新编译,面向接⼝开发 的意义将大打折扣
问题二:service 层代码没有竟然还没有进行事务控制,如果转账过程中出现异常,将可能导致 数据库数据错乱,后果可能会很严重,尤其在金融业务
问题解决思路:
针对问题一思考: 实例化对象的方式除了 new 之外,还有什么技术,反射 (需要把类的全限定类名配置在xml中)
考虑使用设计模式中的工⼚模式解耦合,另外项⽬中往往有很多对象需要实例化,那就在工⼚中使 用反 射技术实例化对象,工⼚模式很合适,当然,这里工厂并非一定操作单纯的对象,map也是一个对象
针对问题二思考:
service 层没有添加事务控制,怎么办,既然没有事务就添加上事务控制,⼿动控制 JDBC 的Connection 事务,但要注意将Connection和当前线程绑定(即保证一个线程只有一个Connection,这样操作才针对的是同一个 Connection,进而控制的是同一个事务,而不是不同的事务)
现在我们来操作案例(上面图片想象即可),在64章博客中拿取一个案例即可(或者看后面的跟着来,虽然基本是拿取的)
这里给出具体的流程:
先导入依赖:
<dependencies>
<dependency>
<groupId>dom4jgroupId>
<artifactId>dom4jartifactId>
<version>1.6.1version>
dependency>
<dependency>
<groupId>jaxengroupId>
<artifactId>jaxenartifactId>
<version>1.1.6version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
创建类和接口:
package com.lagou.dao;
public interface IUserDao {
public void save();
}
package com.lagou.dao.Impl;
import com.lagou.dao.IUserDao;
public class IUserDaoImpl implements IUserDao {
public void save() {
System.out.println("dao被调用了,保存成功...");
}
}
public interface IUserService {
public void save();
}
public class IUserServiceImpl implements IUserService {
IUserDao userDao;
public IUserServiceImpl(IUserDao userDao) {
this.userDao = userDao;
}
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
public void save() {
System.out.println(1);
userDao.save();
}
}
创建工厂类BeanFactory:
public class BeanFactory {
private static Map<String, Object> iocmap = new HashMap<>();
static {
InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
SAXReader saxReader = new SAXReader();
try {
Document read = saxReader.read(resourceAsStream);
String xpath = "//bean";
List<Element> list = read.selectNodes(xpath);
for (Element element : list) {
String id = element.attributeValue("id");
String aClass = element.attributeValue("class");
Object o = Class.forName(aClass).newInstance();
iocmap.put(id, o);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Object getBean(String beanId) {
Object o = iocmap.get(beanId);
return o;
}
}
创建测试类:
public class SpringTest {
IUserService userService = (IUserService) BeanFactory.getBean("ServiceImpl");
@Test
public void test1() {
userService.save();
}
}
创建配置文件beans.xml:
<beans>
<bean id="userDao" class="com.lagou.dao.Impl.IUserDaoImpl">
bean>
<bean id="ServiceImpl" class="com.lagou.service.Impl.IUserServiceImpl">
<property name="userDao" ref="userDao">property>
bean>
beans>
执行测试类的方法,若打印了说明操作成功(对应的userDao还没有进行注入(使用DI方式),只是操作了IOC的方式,DI还没有利用)
现在开始我们将操作DI
首先改变配置文件,修改如下:
<beans>
<bean id="userDao" class="com.lagou.dao.Impl.IUserDaoImpl">
bean>
<bean id="ServiceImpl" class="com.lagou.service.Impl.IUserServiceImpl">
<property name="userDao" ref="userDao">property>
bean>
beans>
而修改读取配置文件的类之前,我们首先需要先执行一下,然后看看还是否打印,很明显他还是打印的,只是对应的配置没有获取而已,那么现在我们改变对应的读取配置文件的BeanFactory操作:
package com.lagou.utils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BeanFactory {
private static Map<String, Object> iocmap = new HashMap<>();
static {
InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
SAXReader saxReader = new SAXReader();
try {
Document read = saxReader.read(resourceAsStream);
String xpath = "//bean";
List<Element> list = read.selectNodes(xpath);
for (Element element : list) {
String id = element.attributeValue("id");
String aClass = element.attributeValue("class");
Object o = Class.forName(aClass).newInstance();
iocmap.put(id, o);
}
List<Element> property = read.selectNodes("//property");
for (int i = 0; i < property.size(); i++) {
Element element = property.get(i);
String name = element.attributeValue("name");
String ref = element.attributeValue("ref");
Element parent = element.getParent();
String id = parent.attributeValue("id");
Object o = iocmap.get(id);
Method[] methods = o.getClass().getMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
String name1 = method.getName();
if (name1.equalsIgnoreCase("set" + name)) {
method.invoke(o, iocmap.get(ref));
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static Object getBean(String beanId) {
Object o = iocmap.get(beanId);
return o;
}
}
然后再将对应IUserServiceImpl的构造方法去掉,然后我们直接的执行测试类的方法,若发现调用了说明注入成功,DI操作完毕(利用容器,那么从容器层面说明的),IOC则直接保存对象到容器(对象的层面)
至此通过IOC和DI解决了对应的问题一(包含了硬编码的问题(只需要改变配置文件,就可以所有对应地方都操作,且可以随意写包名,而直接的反射和new(导入的)只能操作一个地址,不随意,所以认为是硬编码),前置是new,然后字符串,最后解决硬编码),IOC解决,DI来赋值(问题一主要是解决,而赋值可以进行省略直接的编写,即进一步的省略)
接下来我们来解决问题二(AOP的利用):
要解决问题二,首先我们需要一个场景,首先导入依赖:
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
创建数据库的sql:
CREATE DATABASE springtext CHARACTER SET utf8;
USE springtext;
CREATE TABLE spring(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
money INT
);
INSERT INTO spring VALUES(1,'张三',1000);
INSERT INTO spring VALUES(2,'李四',1000);
现在我们来编写或者修改IUserDao和其实现类的对应的代码,代码如下:
package com.lagou.dao;
public interface IUserDao {
public void dao();
public void in(int id, int money);
public void ou(int id, int money);
}
package com.lagou.dao.Impl;
import com.lagou.dao.IUserDao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class IUserDaoImpl implements IUserDao {
@Override
public void dao() {
System.out.println("dao调用了");
}
public void in(int id, int money) {
Connection con = null;
PreparedStatement ps = null;
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/springtext?characterEncoding=UTF-8&useSSL=false";
con = DriverManager.getConnection(url, "root", "123456");
String sql = "UPDATE spring SET money = money + ? WHERE id = ?";
ps = con.prepareStatement(sql);
ps.setInt(1, money);
ps.setInt(2, id);
ps.executeUpdate();
ps.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void ou(int id, int money) {
Connection con = null;
PreparedStatement ps = null;
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/springtext?characterEncoding=UTF-8&useSSL=false";
con = DriverManager.getConnection(url, "root", "123456");
String sql = "UPDATE spring SET money = money - ? WHERE id = ?";
ps = con.prepareStatement(sql);
ps.setInt(1, money);
ps.setInt(2, id);
ps.executeUpdate();
ps.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
编写或者修改IUserService及其实现类:
package com.lagou.service;
public interface IUserService {
public void dao();
public void inou(int inid, int ouid, int money);
}
package com.lagou.service.Impl;
import com.lagou.dao.IUserDao;
import com.lagou.service.IUserService;
public class IUserServiceImpl implements IUserService {
IUserDao userDao;
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
@Override
public void dao() {
System.out.println(1);
userDao.dao();
}
@Override
public void inou(int inid, int ouid, int money) {
userDao.in(inid, money);
System.out.println("中间");
userDao.ou(ouid, money);
}
}
测试类SpringTest也改一改:
package com.lagou.test;
import com.lagou.service.IUserService;
import com.lagou.utils.BeanFactory;
import org.junit.Test;
public class SpringTest {
IUserService userService = (IUserService) BeanFactory.getBean("ServiceImpl");
@Test
public void test1() {
System.out.println(1);
userService.dao();
}
}
为了进行测试,我们再次的创建方法:
package com.lagou.test;
import com.lagou.service.IUserService;
import com.lagou.utils.BeanFactory;
import org.junit.Test;
public class SpringTest {
IUserService userService = (IUserService) BeanFactory.getBean("ServiceImpl");
@Test
public void test1() {
System.out.println(1);
userService.dao();
}
@Test
public void test2() {
System.out.println(2);
userService.inou(1, 2, 100);
}
}
执行test2方法,查看数据库是否修改,若修改了,说明操作成功
现在我们来操作问题二的场景,修改对应的代码:
@Override
public void inou(int inid, int ouid, int money) {
userDao.in(inid, money);
System.out.println("中间");
int i= 1/0;
userDao.ou(ouid, money);
}
继续test2方法,若数据出现错误,那么场景创建成功,数据错误,现在我们开始来解决这样的问题
首先我们要知道,事务是由一个连接来操作的,两个连接自然不会是同一个事务,连接就相当于一个会话了
所以我们需要将他们的两次操作由一个连接来完成,那么很明显,根据层的分开,我们的事务一般需要在service里加上而不是在dao中进行操作(他必然是与其他dao分开的)
首先我们在utils包下创建ConnectionUtils类:
package com.lagou.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionUtils {
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
public static Connection getThreadConnection() {
Connection conn = threadLocal.get();
if (conn == null) {
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/springtext?characterEncoding=UTF-8&useSSL=false";
conn = DriverManager.getConnection(url, "root", "123456");
threadLocal.set(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
return conn;
}
public void removeThreadConnection() {
threadLocal.remove();
}
}
至此,一个线程必然是同一个连接,也就使得会操作同一个事务,继续进行修改如下代码:
try {
con = ConnectionUtils.getThreadConnection();
然后去掉对应的con.close();(再次的得到就不能进行操作了,如con.prepareStatement(sql);),然后继续操作,首先去掉int i= 1/0;,若数据库数据发生改变,那么说明初始配置操作成功,接下来我们来操作事务(修改对应的代码):
package com.lagou.service.Impl;
import com.lagou.dao.IUserDao;
import com.lagou.service.IUserService;
import com.lagou.utils.ConnectionUtils;
import java.sql.SQLException;
public class IUserServiceImpl implements IUserService {
IUserDao userDao;
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
@Override
public void dao() {
System.out.println(1);
userDao.dao();
}
@Override
public void inou(int inid, int ouid, int money) {
try {
ConnectionUtils.getThreadConnection().setAutoCommit(false);
userDao.in(inid, money);
System.out.println("中间");
int i = 1 / 0;
userDao.ou(ouid, money);
ConnectionUtils.getThreadConnection().commit();
} catch (Exception e) {
e.printStackTrace();
try {
ConnectionUtils.getThreadConnection().rollback();
throw e;
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}
注意:上面的事务可以利用一个类来完成,这里就不进行操作了,自己可以进行修改
现在开始执行,若数据没有变化,那么事务回滚成功,注意:大多数回滚是需要自己进行操作的,否则单纯的报错一般不会进行回滚,但是并非不回滚数据就会变,由于报错后面不操作,那么他就不会进行提交,这也使得有些地方,没有回滚,数据却也没有变化的原因,其中大多数框架中,我们也会说成报错就回滚,实际上底层是操作手动回滚的而不是真的报错就回滚,所以我们也会认为报错就会操作回滚(可以这样的认为,因为他们(一般包括框架)基本操作事务时,都这样操作报错就回滚的)
问题二大致解决,为什么说大致呢,因为现在有个问题,如果有很多这样的方法,那么是否都需要写上对应的关闭事务,提交事务和回滚事务呢,很明显,都要的,既然都要那么非常麻烦,所以这里就是AOP要核心解决的问题(在问题二中的部分核心问题,第一个核心是相同连接,第二个核心是AOP要解决的,所以说使用AOP解决问题二也不过分)
现在开始操作:
我们知道一个类一般都会有对应的实现接口,而在实现接口,且每个接口方法中进行同样的操作的解决方式我们一般都会使用jdk动态代理,同样的,这里我们也进行使用,在utils包下创建一个类Proxy:
package com.lagou.utils;
import com.lagou.service.IUserService;
import com.lagou.service.Impl.IUserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyIn {
public static IUserService JdkProxy(Object o) {
IUserService o1 = (IUserService) Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
System.out.println(3);
ConnectionUtils.getThreadConnection().setAutoCommit(false);
method.invoke(o, args);
ConnectionUtils.getThreadConnection().commit();
} catch (Exception e) {
e.printStackTrace();
ConnectionUtils.getThreadConnection().rollback();
}
return null;
}
});
return o1;
}
}
然后改变IUserServiceImpl的方法:
@Override
public void inou(int inid, int ouid, int money) {
userDao.in(inid, money);
System.out.println("中间");
int i = 1 / 0;
userDao.ou(ouid, money);
}
改变测试类方法:
@Test
public void test2() {
IUserService iUserService = ProxyIn.JdkProxy(userService);
iUserService.inou(1,2,100);
}
执行后,若数据还是没有变化,说明操作成功
实际上上面你可以选择使用单例模式来操作,使得我们只能操作一个类里面的,而不是占用静态名称,或者说防止其他人直接的进行调用来使用(实际上静态大多都会限制不是静态的使用,所以除非他不会利用其他变量,否则一般我们不会使用静态,因为一个类里面都是静态的,是不好扩展的,不能继承静态的(在于必须也对子操作静态,那么自然没有继承的说法了),即操作不了super,所以我们一般一个类里面使用静态时,不会使用很多,也通常需要在不会利用其他变量的前提下,当然,只是一种说明而已,你可以选择在里面创建对象来使用,虽然并不好),但是这里只要求说明原理,并不要求什么模式,所以就不操作了
实际上还有一个代理模式:CGLIB动态代理
实际上代理模式大多数都是操作反射来完成的,我们也可以利用反射来自己实现代理模式,具体实现方式可以百度(需要很多反射的知识,甚至可能有特殊的操作,使得可以改变原来的类的结构,如补充实现接口,继承类等等)
现在我们来利用CGLIB动态代理:
继续回到utils包下,创建CglibIn类:
前提是需要依赖:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.5.RELEASEversion>
dependency>
也就是说他并不是JDK自带的,是其他依赖包里面的,我们看看这个类:
package com.lagou.utils;
import com.lagou.service.IUserService;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibIn {
public static IUserService CglibProxy(Object o) {
IUserService o1 = (IUserService) Enhancer.create(o.getClass(), new MethodInterceptor() {
@Override
public Object intercept(Object oo, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
try {
System.out.println(3);
ConnectionUtils.getThreadConnection().setAutoCommit(false);
method.invoke(o, objects);
ConnectionUtils.getThreadConnection().commit();
} catch (Exception e) {
e.printStackTrace();
ConnectionUtils.getThreadConnection().rollback();
}
return null;
}
});
return o1;
}
}
在测试类中加上如下:
@Test
public void test3() {
IUserService iUserService = CglibIn.CglibProxy(userService);
iUserService.inou(1,2,100);
}
进行测试,若数据没有变化,说明操作成功
这里要注意,由于自身能打印(toString也会进行触发,所以对应的invoke里面的参数不要写当前代理类(他也是存在对应方法的),否则是会无限循环的)
上面我们测试完成,那么AOP就说明完成,总结:IOC和DI(是i的大写)通过配置来完成,AOP通过代理来完成,当然,AOP也可以通过配置来得到类,然后使用,或者自动的改变对应的map集合相关方法,变成代理类等等操作,一般来说,我们不会将代理类进行打印返回,而是将要代理的原来的对象类进行返回(代理类打印自身一般也会触发拦截的,代理是特殊的,具体是保证不会给其他人直接使用)
当然了Spring主要是为了将实例自己创建,所以我们也可以将APO相关的类放在配置文件中,具体实现参照前面的userDao的注入,这里就不多说了
当然,由于这里只是操作实现,对应的代理并没有什么流程可言,如专门操作事务的类和代理类等等,但是基本为了方便就使用了静态,如同样是操作事务的操作和代理操作等等,注意即可,当然64章博客开始的内容基本都说明了,且有顺序
如果在框架中,需要知道他要什么值,可以ctrl+左键即可,以scope为例子,是:
当然,如果是xsd:integer,那么你也只能写数字了(默认是String的,只是转换成String(一般直接赋值)或者Integer,String一般直接赋值不转换)
至此IOC和AOP的相关代码都手写完成
这里最好复习64章开始的内容,是为后面说明做准备的
现在我们来补充对应博客的内容
Spring IOC⾼级特性:
lazy-Init 延迟加载:
我们知道mybatis有延迟加载,代表对实际上Spring也是有的,只是他代表对实例的延迟创建
Bean的延迟加载(延迟创建):
ApplicationContext 容器的默认行为是在启动服务器时将所有 singleton bean (单例bean)提前进行实例化放入map集合中(多例不放入,且与map无关,所以我们一般不会考虑多例延迟加载的情况,虽然他也是使用就会创建),提前 实例化意味着作为初始化过程的一部分,在前面就是在static代码块中进行操作,ApplicationContext 实例会创建并配置所有的singleton bean
这里我首先给出测试环境,首先创建项目,给出依赖:
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.5.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
项目图如下:
package com.domain;
public class Account {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
package com.test;
import com.domain.Account;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test1 {
@Test
public void text1(){
ApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
Account account = (Account) classPathXmlApplicationContext.getBean("ac");
System.out.println(account);
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="ac" class="com.domain.Account">bean>
beans>
执行一下,若有数据,代表环境操作成功
对于上面的延迟加载,一般这样设置,比如:
<bean id="testBean" class="cn.lagou.LazyBean" />
<bean id="testBean" calss="cn.lagou.LazyBean" lazy-init="false" />
lazy-init=“false”,立即加载,表示在spring启动时,立刻进行实例化,这是默认的值
如果不想让一个singleton bean 在 ApplicationContext实现初始化时被提前实例化,那么可以将bean设置为延迟实例化
<bean id="testBean" calss="cn.lagou.LazyBean" lazy-init="true" />
设置 lazy-init 为 true 的 bean 将不会在 ApplicationContext 启动时提前被实例化,而是第一次向容器 通过 getBean 索取 bean 时实例化的,看起来就是多例了,但他是多例,即多人操作会不同的,而不是相同,相当于我们在博客中学习的:
BeanFactory xmlBeanFactory = new XmlBeanFactory(new
ClassPathResource("applicationContext.xml"));
如果一个设置了立即加载的 bean1,引用了一个延迟加载的 bean2 ,那么 bean1 在容器启动时被实例 化,而 bean2 由于被 bean1 引用,所以也被实例化,这种情况也符合延时加载的 bean 在第一次调用 时才被实例化的规则(根据前面的代码可以知道操作了getBean)
但是在前面我们手写的对应代码中知道,他首先是从对应的map中获取,可是没有对应的实例,那么我们哪里是需要进行修改的,那么很明显,设置延迟时,一般在Spring中有存在对应的编号,首先他并不会放入map,而对应的getBean调用时,内部也会判断这个编号,从而创建实例放入map,再返回,这就是延迟加载的机制
也可以在容器层次中通过在 元素上使用 “default-lazy-init” 属性来控制延时初始化,如下面配置:
<beans default-lazy-init="true">
beans>
他就相当于给所有的bean加上lazy-init=“true”,当然,如果bean自己设置了lazy-init=“false”,那么按照他的lazy-init="false"为主,当然,随着版本的变化,他可能是以default-lazy-init="true"为主
如果一个 bean 的 scope 属性为 scope=“pototype” 时,即使设置了 lazy-init=“false”,容器启动时也不 会实例化bean,而是调用 getBean 方法实例化的,因为多例不考虑是否延迟,即无作用
应用场景:
1:开启延迟加载一定程度提⾼容器启动和运转性能(相对于原来的资源多了,自然相对来说也会或多或少提高性能,这也是为什么提供了beans标签上可以加default-lazy-init="true"属性的原因,大多数针对硬盘只有不足时可能会明显的影响性能,通常足够不会,针对JVM内存也是如此,只有快要不足时,才会考虑性能的出现,但是资源被占用,需要的判断或者移动放入也会变多,所以或多或少也会减低一点性能,且对与存储的地方而言,因为需要找寻他给你,所以总体来说,存放东西就一定会影响性能,只是非常小而已)
2:对于不常使用的 Bean 设置延迟加载,这样偶尔使用的时候再加载,不必要从一开始该 Bean 就占 用资源
实际上在源码上,可以看看:
BeanFactory与ApplicationContext区别:
BeanFactory是Spring框架中IoC容器的顶层接⼝,它只是用来定义一些基础功能,定义一些基础规范,而ApplicationContext是它的一个⼦接⼝,所以ApplicationContext是具备BeanFactory提供的全部功能的,通常,我们称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的⾼级接⼝,比BeanFactory要拥有更多的功能,比如说国际化⽀持和资源访问(xml,java配置类)等等
实际上在博客学习中也具体说明过,这里可以给出图片:
当然,这个图片是网上找的,并且比较旧,但是也大致的给出的具体的架构关联
FactoryBean 和 BeanFactory:
BeanFactory接⼝是容器的顶级接⼝,定义了容器的一些基础行为,负责生产和管理Bean的一个工⼚, 具体使用它下面的⼦接⼝类型,比如ApplicationContext
此处我们重点分析FactoryBean,Spring中Bean有两种,一种是普通Bean,一种是工⼚Bean(FactoryBean,工厂有两种(静态和普通)),FactoryBean可以生成 某一个类型的Bean实例(返回给我们),也就是说我们可以借助于它⾃定义Bean的创建过程
Bean创建的三种方式中的工厂静态方法和工厂(普通)实例化方法和FactoryBean作用类似,FactoryBean使用较多,尤 其在Spring框架一些组件中会使用,还有其他框架和Spring框架整合时使用
我们可以自定义Bean的创建过程(也可以叫做工厂),看如下这个接口:
我们再前面测试的环境中的com包下,创建factory.FactoryBean接口:
package com.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T> extends org.springframework.beans.factory.FactoryBean {
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
package org.springframework.beans.factory;
import org.springframework.lang.Nullable;
public interface FactoryBean<T> {
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
然后我们再domain包下创建Company:
package com.domain;
public class Company {
private String name;
private String address;
private int scale;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getScale() {
return scale;
}
public void setScale(int scale) {
this.scale = scale;
}
@Override
public String toString() {
return "Company{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", scale=" + scale +
'}';
}
}
然后在factory包下创建CompanyFactoryBean类:
package com.factory;
import com.domain.Company;
public class CompanyFactoryBean implements FactoryBean<Company> {
private String companyInfo;
public void setCompanyInfo(String companyInfo) {
this.companyInfo = companyInfo;
}
@Override
public Company getObject() throws Exception {
Company company = new Company();
String[] strings = companyInfo.split(",");
company.setName(strings[0]);
company.setAddress(strings[1]);
company.setScale(Integer.parseInt(strings[2]));
return company;
}
@Override
public Class<?> getObjectType() {
return Company.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
创建好后,我们在xml中加上如下:
<bean id="fac" class="com.factory.CompanyFactoryBean">
<property name="companyInfo" value="哈哈,heihie,11">property>
bean>
这里大多数你可能会认为是实现类,实际上由于对应的类实现了FactoryBean(package org.springframework.beans.factory;里面的),且在map中会判断是否实现这个,从而不将这个类放入map,而是将对应getObject()方法的值放入map
为了进行验证,我们测试:
package com.test;
import com.domain.Account;
import com.domain.Company;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
public class Test1 {
@Test
public void text1() {
ApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
Company company = (Company) classPathXmlApplicationContext.getBean("fac");
System.out.println(company);
}
}
可以知道对方打印了对应的信息,且是getObject()方法的值,也经过测试,如果没有实现对应的接口,那么就是对应的类对象(记得改一改),而不是执行getObject()方法的值
若我们不需要他操作对应的getObject()方法的值,可以操作如下:
CompanyFactoryBean company = (CompanyFactoryBean) classPathXmlApplicationContext.getBean("&fac");
System.out.println(company);
这样就是对应的实例了,而不是getObject()方法的值,实际上在前面的singletonObjects中并没有,因为这里是另外的地方来获取的
后置处理器:
Spring提供了两种后处理bean的扩展接⼝,分别为 BeanPostProcessor 和BeanFactoryPostProcessor,两者在使用上是有所区别的
由于我们可以通过工⼚初始化(BeanFactory,这里代表操作xml或者配置类的工厂)—> Bean对象
在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置处理做一些事情
在Bean对象实例化(并不是Bean的整个生命周期完成)之后可以使用BeanPostProcessor进行后置处 理做一些事情
注意:对象不一定是springbean(比如没有放入map里面的对象),而springbean一定是个对象
springbean更加详细的生命周期是:
也可以看图(虽然没有给出BeanFactoryPostProcessor接口的处理方法):
那么为了进行验证,我们改变前面的Account类,操作如下:
package com.domain;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class Account implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {
@Override
public void setBeanName(String s) {
System.out.println("注册我成为bean时定义的id:" + s);
System.out.println("BeanNameAware");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("可以管理我的BeanFactory:" + beanFactory);
System.out.println("BeanFactoryAware");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("高级容器接口:" + applicationContext);
System.out.println("ApplicationContextAware");
}
}
测试类我们修改成如下:
package com.test;
import com.domain.Account;
import com.domain.Company;
import com.factory.CompanyFactoryBean;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
public class Test1 {
@Test
public void text1() {
ApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(1);
}
}
执行看看结果:
现在我们来看看BeanPostProcessor接口,BeanPostProcessor是针对Bean级别的处理,可以针对某个具体的Bean
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
该接⼝提供了两个方法,分别在Bean的初始化方法前和初始化方法后执行,具体这个初始化方法指的是 什么方法,类似我们在定义bean时,定义了init-method所指定的方法,但是若实现了他,就都在初始化方法后操作了,且是在所有的初始化操作后才操作,那么实现了他的初始化必然比没有实现他的初始化先操作,然后其他的初始化都在这个实现接口的初始化的前方法(先给出所有)和后方法中间,这里你可能并不明白为什么,到后面自己测试时就知道了(看后面的"细节流程如下",或者"现在给出所有的流程")
现在我们操作xml:
<bean id="ac" class="com.domain.Account" init-method="init">bean>
在Account类中加上如下:
public void init(){
System.out.println("init");
}
定义一个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进行处理,如果要对 具体的某个bean处理,可以通过方法参数判断,两个类型参数分别为Object和String,第一个参数是每 个bean的实例,第二个参数是每个bean的id属性的值(或者name,前提是id不存在),所以我们可以通过第二个参数,来判 断我们将要处理的具体的bean
现在来测试,创建一个类User(在domain包下):
package com.domain;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanPostProcessor {
@Override
public void setBeanName(String s) {
System.out.println("User-注册我成为bean时定义的id:" + s);
System.out.println("User-BeanNameAware");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("User-可以管理我的BeanFactory:" + beanFactory);
System.out.println("User-BeanFactoryAware");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("User-高级容器接口:" + applicationContext);
System.out.println("User-ApplicationContextAware");
}
public void init() {
System.out.println("User-init");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("User-前");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("User-后");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
在xml中加上如下:
<bean id="acc" class="com.domain.User" init-method="init">bean>
执行看看结果:
然而如果对方的类实现了BeanPostProcessor接口,那么就不会出现在对应的处理中,所以若上面的该接口方法里面写上如下:
System.out.println(bean);
System.out.println(beanName);
后面的名称只有fac了(上面的也就是fac),若没有实现对应的接口,那么考虑前面的"分别在Bean的初始化方法前和初始化方法后执行",来操作初始化方法了
至此,改BeanPostProcessor接口说明完毕
细节流程如下:
然后继续给Account类进行实现接口,调用InitializingBean接口的afterPropertiesSet方法,可以在初始化之前执行,若没有实现BeanPostProcessor接口,那么在对应的前方法打印后,我来执行,然后初始化执行
我们继续实现BeanFactoryPostProcessor接口,他的实现导致与实现BeanPostProcessor接口一样的,但是他的方法只是操作当前类,不会被其他人调用
现在给出所有的流程:
对应的Account类:
package com.domain;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class Account implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanPostProcessor, InitializingBean, BeanFactoryPostProcessor {
@Override
public void setBeanName(String s) {
System.out.println("BeanNameAware");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("ApplicationContextAware");
}
public void init() {
System.out.println("init");
}
public void tt() {
System.out.println("tt");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("前");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("后");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("后后");
}
}
对应的类User:
package com.domain;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanPostProcessor, InitializingBean, BeanFactoryPostProcessor {
@Override
public void setBeanName(String s) {
System.out.println("User-BeanNameAware");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("User-BeanFactoryAware");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("User-ApplicationContextAware");
}
public void init() {
System.out.println("User-init");
}
public void tt() {
System.out.println("User-tt");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("User-前");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("User-后");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("User-InitializingBean");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("User-后后");
}
}
对应的Test类:
package com.domain;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class Test implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {
@Override
public void setBeanName(String s) {
System.out.println("Test-BeanNameAware");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Test-BeanFactoryAware");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("Test-ApplicationContextAware");
}
public void init() {
System.out.println("Test-init");
}
public void tt() {
System.out.println("Test-init");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Test-InitializingBean");
}
}
对应的测试类:
package com.test;
import com.domain.Account;
import com.domain.Company;
import com.factory.CompanyFactoryBean;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
public class Test1 {
@Test
public void text1() {
ApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(1);
Object fac = classPathXmlApplicationContext.getBean("fac");
System.out.println(5);
}
}
对应的配置文件:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="ac" class="com.domain.Account" init-method="init" destroy-method="tt">bean>
<bean id="acc" class="com.domain.User" init-method="init" destroy-method="tt">bean>
<bean id="facc" class="com.domain.Test" init-method="init" destroy-method="tt">
bean>
<bean id="fac" class="com.domain.Test" init-method="init" destroy-method="tt">
bean>
beans>
现在我们来看看结果:
至此,大致流程给出完毕
这里还要说明一下BeanFactoryPostProcessor:针对整个Bean的工⼚进行处理,其对应接口只有一个,且方法参数为ConfigurableListableBeanFactory,其中有个方法名为getBeanDefinition的方法,我们可以根据此方法,找到我们定义bean 的BeanDefinition对象,然后我们可以对定义的属性进行修改
BeanDefinition对象(他一般是接口)中的方法名字类似我们bean标签的属性,setBeanClassName对应bean标签中的class属性,所以当我们拿到BeanDefinition对象时,我们可以⼿动修改bean标签中所定义的属性值
BeanDefinition对象(实现该接口的对象,具体是谁可以百度):我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为一个 JavaBean, 这个JavaBean 就是 BeanDefinition,在后面会说明的他的加载过程
注意:调用 BeanFactoryPostProcessor 方法时,这时候bean还没有实例化,此时 bean 刚被解析成BeanDefinition对象,但也只是针对没有实现对应接口的类,看对应的参数信息就知道了(初始化之后才是(class的值变的)实例的产生,虽然前面可能是实例了,但是并不完全,这里只考虑完全的,即放入map中的,即初始化后才会放入map中)
Spring IOC源码深度剖析:
一般来说我们ctrl+左键是看class文件(反编译,idea看的基本都是),可能会与真正的源码有点问题(反编译并不一定都对,可以认为是失帧)
所以我们需要直接的源码,那么我们来进行下载:首先是github上搜索spring-framework,找到点击第一个spring-projects/spring-framework,这里直接给出地址:https://github.com/spring-projects/spring-framework,找到5.1.x版本,下载ZIP文件即可
然后我们解压,现在我们还要再下载一个工具:gradle(类似于maven,也拥有maven的一些规定),为什么要他,这是因为现在大多数的源码基本都是由他来管理了,而不是maven,所以这里需要下载,可能你并没有学习过,这里给出一个视频地址可以来学习学习:
https://www.bilibili.com/video/BV1yT41137Y7/?spm_id_from=333.337.search-card.all.click&vd_source=5ea24d17d411aaa69d753a5f20d6e0a2
还有几个博客可以学习构建:
https://blog.csdn.net/weixin_44167408/article/details/121769949
https://blog.51cto.com/u_15773967/5638868
https://blog.csdn.net/tuomazhao/article/details/105400234(建议这个)
在视频(这里并没有说明博客)中虽然说明必须对应版本,但是其实通常是可以高于对方版本的,比如gradle 的版本可以高于等于idea 版本(但一般建议等于,虽然大多数都是可以,只是对方在升级以后的版本时,可能随时舍弃兼容低版本的功能),jdk也可以高于等于对应的版本(一般是高于等于8),实际上将gradle看成maven就行了,只是某些不同而已,但是最终的结果还是相同的
相关文件的下载地址:
链接:https://pan.baidu.com/s/1I1S_vut_-VRhsNj_hH7e1A
提取码:alsk
当然,对应的源码只是源代码,通常是需要编译的,并且一般需要顺序(其中一个编译可能需要其他的jar,且一般只是当前项目的(但是需要编译,这里与maven是不同的一点),因为spring官方给出的源码中,他既然是下载的,所以通常并不提供远程jar包)
一般的顺序是spring-core,spring-oxm,sprinh-context,spring-beans,spring-aspects,spring-aop等等顺序,当然,可能顺序改变了,但是一般core通常都需要先编译,其他的顺序一般不固定,编译方式(gradle的编译与maven是不同的,必须编译后才可提供给其他项目,否则其他项目一般获取不了,当然随着时代的发展,可能也会借鉴maven的,所以具体如何,还是需要自己测试):
双击上面的compileTestJava即可编译,每一个项目基本都是双击他,好了现在我们来直接的使用该源码来操作spring,在该整个项目下再创建子模块,项目如下:
对应的build.gradle:
plugins {
id 'java'
}
group 'org.springframework'
version '5.1.21.BUILD-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.testng:testng:7.1.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
compile(project(":spring-context"))
compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.8.6'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
对应的ItBean类:
package com.lagou.edu;
public class ItBean {
private LagouBean lagouBean;
public void setLagouBean(LagouBean lagouBean) {
this.lagouBean = lagouBean;
}
public ItBean(){
System.out.println("ItBean 构造器...");
}
}
对应的LagouBean类:
package com.lagou.edu;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class LagouBean implements InitializingBean, ApplicationContextAware {
private ItBean itBean;
public void setItBean(ItBean itBean) {
this.itBean = itBean;
}
public LagouBean(){
System.out.println("LagouBean 构造器...");
}
public void afterPropertiesSet() throws Exception {
System.out.println("LagouBean afterPropertiesSet...");
}
public void print() {
System.out.println("print方法业务逻辑执行");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("setApplicationContext....");
}
}
对应的application.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="lagouBean" class="com.lagou.edu.LagouBean">
<property name="itBean" ref="itBean">property>
bean>
<bean id="itBean" class="com.lagou.edu.ItBean">
<property name="lagouBean" ref="lagouBean">property>
bean>
beans>
对应的IocTest类:
import com.lagou.edu.LagouBean;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IocTest {
@Test
public void testIoC() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");
LagouBean lagouBean = applicationContext.getBean(LagouBean.class);
System.out.println(lagouBean);
}
}
进行执行,若出现类似的如下,代表操作成功(即也代表spring源码也是正确的):
我们来操作多例,看看是否存在循环依赖:
<bean id="lagouBean" class="com.lagou.edu.LagouBean" scope="prototype">
<property name="itBean" ref="itBean">property>
bean>
<bean id="itBean" class="com.lagou.edu.ItBean" scope="prototype">
<property name="lagouBean" ref="lagouBean">property>
bean>
执行后,可以明显的发现,他发生了报错,也就是说,的确存在循环依赖,但是他的报错是监测的,所以是直接的报错,而不是因为堆空间形成的错误
现在我们来ctrl+左键进入,可以明显的发现,与class反射不同的是,他出现了对应的注释,在jdk自带的类中也是这样的(在某些情况下,可能不会,具体可以百度),这就是class和java的显示区别,因为对方的jar包基本只提供了class(虽然jar基本都是提供class,可能会提供java,具体可以百度),而没有java,当然,class反编译的显示问题是很难看见的,所以我们了解即可
Spring IoC容器初始化主体流程:
Spring IoC的容器体系:
IoC容器是Spring的核心模块,是抽象了对象管理、依赖关系管理的框架解决方案,Spring 提供了很多 的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器 必须遵从 的一套原则,具体的容器实现可以增加额外的功能,比如我们常用到的ApplicationContext,其下更具 体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等一系列的内容,AnnotationConfigApplicationContext 则是包含了注解解析等一系列的内容,Spring IoC 容器继承体系 ⾮常聪明,需要使用哪个层次用哪个层次即可,不必使用功能大而全的
BeanFactory 顶级接⼝方法栈如下:
最后一个是&,前面操作的".getBean(“&fac”);“是否还记得呢,就是对应的作用,而不是操作工厂(我们不需要他操作对应的getObject()方法的值),而由于在前面,所以一般我们称为"工厂bean前缀”(前提是操作了对应的工厂,否则是会报错的,即单纯的不识别该符号,内部错误,一般在bean初始化放入map时就会报错了)
BeanFactory 容器继承体系(当然,版本不同,这个继承可能也不同):
通过其接⼝设计,我们可以看到我们一贯使用的 ApplicationContext 除了继承BeanFactory的⼦接⼝, 还继承了ResourceLoader、MessageSource等接⼝,因此其提供的功能也就更丰富了,下面我们以 ClasspathXmlApplicationContext(ApplicationContext的子类,上面只是说明主要的接口)为例,深⼊源码说明 IoC 容器的初始化流程
Bean生命周期关键时机点:
思路:创建一个类 LagouBean ,让其实现⼏个特殊的接⼝,并分别在接⼝实现的构造器、接⼝方法中 断点,观察线程调用栈,分析出 Bean 对象创建和管理关键点的触发时机
修改LagouBean类:
package com.lagou.edu;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class LagouBean implements InitializingBean {
private ItBean itBean;
public void setItBean(ItBean itBean) {
this.itBean = itBean;
}
public LagouBean() {
System.out.println("LagouBean 构造器...");
}
public void afterPropertiesSet() throws Exception {
System.out.println("LagouBean afterPropertiesSet...");
}
}
在对应的edu包下创建MyBeanPostProcessor类:
package com.lagou.edu;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
System.out.println("BeanPostProcessor 实现类构造函数...");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("lagouBean".equals(beanName)) {
System.out.println("BeanPostProcessor 实现类 postProcessBeforeInitialization 方法被调用中......");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("lagouBean".equals(beanName)) {
System.out.println("BeanPostProcessor 实现类 postProcessAfterInitialization 方法被调用中......");
}
return bean;
}
}
同样的还在该包下创建MyBeanFactoryPostProcessor类:
package com.lagou.edu;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public MyBeanFactoryPostProcessor() {
System.out.println("BeanFactoryPostProcessor的实现类构造函数...");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor的实现方法调用中......");
}
}
application.xml修改成如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="lagouBean" class="com.lagou.edu.LagouBean"/>
<bean id="myBeanFactoryPostProcessor" class="com.lagou.edu.MyBeanFactoryPostProcessor"/>
<bean id="myBeanPostProcessor" class="com.lagou.edu.MyBeanPostProcessor"/>
beans>
IocTest类如下(虽然基本没有改变):
import com.lagou.edu.LagouBean;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IocTest {
@Test
public void testIoC() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");
LagouBean lagouBean = applicationContext.getBean(LagouBean.class);
System.out.println(lagouBean);
}
}
现在开始进行分析,分析 Bean 的创建是在容器初始化时还是在 getBean 时
既然实例是创建好的,那么我们往前走,分析分析构造函数调用情况:
为什么我知道是在AbstractApplicationContext类中呢,我们看这里:
我们点击左边的地方,会到对应的代码那里去,我们在后面可以找到这个:
后面的基本是操作测试类了,所以这个类是入口,他最终会操作到构造方法(一般在下面的说明先执行的)
分析 InitializingBean 之 afterPropertiesSet 初始化方法调用情况:
分析BeanFactoryPostProcessor 初始化和调用情况:
给MyBeanFactoryPostProcessor对应的postProcessBeanFactory方法打上断点,然后给构造方法打上断点,前面的断点不变,然后进行操作:
可以发现发生了改变
MyBeanFactoryPostProcessor构造方法,postProcessBeanFactory方法都在invokeBeanFactoryPostProcessors(beanFactory);里执行(AbstractApplicationContext对应的refresh方法里面),并且顺序是构造方法,postProcessBeanFactory方法
也符合前面的操作,只是他的方法是invokeBeanFactoryPostProcessors(beanFactory);里执行,另外的可以发现在finishBeanFactoryInitialization(beanFactory);方法里执行,并且发现在finishBeanFactoryInitialization(beanFactory);方法的确在invokeBeanFactoryPostProcessors(beanFactory);里后面,也符合前面的打印信息(前面的"现在我们来看看结果"的打印结果)
分析 BeanPostProcessor 初始化和调用情况:
同理,给MyBeanPostProcessor的对应两个方法打上断点查看结果:
总结:
根据上面的调试分析,我们发现 Bean对象创建的⼏个关键时机点代码层级的调用都在AbstractApplicationContext 类 的 refresh 方法中,可⻅这个方法对于Spring IoC 容器初始化来说相当 关键,汇总如下:
Spring IoC容器初始化主流程:
由上分析可知,Spring IoC 容器初始化的关键环节就在 AbstractApplicationContext#refresh()方法中(#代表对应方法是该类里面的方法) ,我们查看 refresh 方法来俯瞰容器创建的主体流程,主体流程下的具体⼦流程我们后面再来讨论
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}
}
BeanFactory创建流程:
获取BeanFactory⼦流程:
时序图如下:
上面从ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();开始,在之前的refresh方法中哦,具体过程如下:
BeanDefinition加载解析及注册⼦流程:
该⼦流程涉及到如下⼏个关键步骤:
1:Resource定位:指对BeanDefinition的资源定位过程,通俗讲就是找到定义Javabean信息的XML⽂件,并将其封装成Resource对象(你看看对应的postProcessBeanFactory方法的参数是否就是最终得到ConfigurableListableBeanFactory,并且前面也说明过他的方法,即getBeanDefinition的方法)
2:BeanDefinition载⼊ :把用户定义好的Javabean表示为IoC容器内部的数据结构,这个容器内部的数 据结构就是BeanDefinition
3:注册BeanDefinition到 Ioc 容器
过程分析:
⼦流程⼊⼝在 AbstractRefreshableApplicationContext#refreshBeanFactory 方法中,也就是前面的:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
我们在上面进行调试:
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
}
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader, EnvironmentCapable {
@Override
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
for (Resource resource : resources) {
count += loadBeanDefinitions(resource);
}
return count;
}
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int count = 0;
for (String location : locations) {
count += loadBeanDefinitions(location);
}
return count;
}
}
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
}
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
doRegisterBeanDefinitions(ele);
}
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
}
public abstract class BeanDefinitionReaderUtils {
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
}
@SuppressWarnings("serial")
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
}
测试String是否可以写上很多信息:
package com.test;
import org.junit.Test;
public class Test1 {
@Test
public void text1() {
String a = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
System.out.println(a);
}
}
执行一下吧,在一些常见的编程语言中,如Java和C#,String类型的上限是根据底层内存限制来确定的,一般来说,Java中的String对象最大长度是Integer.MAX_VALUE - 2,即2^31 - 2个字符(因为Java中的String对象还需要2个额外的字符用于存储长度信息),在C#中,String对象的最大长度是2GB(即只看具体的内存大小)
前面我们知道了bean的封装以及存放他的一个bean工厂,即ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
他进入的类是如下:
现在我们来看看Bean创建流程(即通过封装好的信息,来创建对象(class)):
我们知道普通的bean(没有实现对应接口的)是在前面的finishBeanFactoryInitialization(beanFactory);方法里面的(一般他的执行完,才是真的创建实例,即这个时候对应的真正map中(从其他移动到这里(前面有说明singletonObjects的变化"交给对应的类的singletonObjects(值)"),一般并没有重新创建,创建一次就行了,在一定程度上也可以说是一级缓存移动到这里)才会存在id和value了),由于主要说明普通的,所以这里我们就看这个方法:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
beanFactory.setTempClassLoader(null);
beanFactory.freezeConfiguration();
beanFactory.preInstantiateSingletons();
}
}
@SuppressWarnings("serial")
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
}
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
}
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
}
他进入的类是(在后面就不给出这样的说明了,因为只需要了解,并且过程中也给出了步骤,就不需要总结一起了,且我们记住这个东西也没有必要,因为对知识毫无用处的):
至此,我们的大致流程操作完毕
lazy-init 延迟加载机制原理:
lazy-init 延迟加载机制分析:
普通 Bean 的初始化是在容器启动初始化阶段执行的,而被lazy-init=true修饰的 bean 则是在从容器⾥ 第一次进行getBean() 时进行触发,Spring 启动的时候会把所有bean信息(包括XML和注解)解析转化成Spring能够识别的BeanDefinition并存到Hashmap⾥供下面的初始化时用,然后对每个BeanDefinition 进行处理,如果是懒加载的则在容器初始化阶段不处理,而是在getBean中处理(可以认为也是前面的填充),其他的则在容器初始化阶段进行初始化并依赖注⼊(前面的填充,基本解决了循环依赖,不用考虑错误)
找到前面的如下:
@SuppressWarnings("serial")
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
}
上面并不是主要的,我们在如下打上断点:
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IocTest {
@Test
public void testIoC() {
System.out.println(BeanFactory.FACTORY_BEAN_PREFIX);
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");
Object lagouBean = (Object) applicationContext.getBean(LagouBean.class);
System.out.println(lagouBean);
}
}
我们进入后到如下:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
return getBean(requiredType, (Object[]) null);
}
@Override
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
if (resolved == null) {
throw new NoSuchBeanDefinitionException(requiredType);
}
return (T) resolved;
}
@Nullable
private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
BeanFactory parent = getParentBeanFactory();
if (parent instanceof DefaultListableBeanFactory) {
return ((DefaultListableBeanFactory) parent).resolveBean(requiredType, args, nonUniqueAsNull);
}
else if (parent != null) {
ObjectProvider<T> parentProvider = parent.getBeanProvider(requiredType);
if (args != null) {
return parentProvider.getObject(args);
}
else {
return (nonUniqueAsNull ? parentProvider.getIfUnique() : parentProvider.getIfAvailable());
}
}
return null;
}
@Nullable
private <T> NamedBeanHolder<T> resolveNamedBean(
ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
Assert.notNull(requiredType, "Required type must not be null");
String[] candidateNames = getBeanNamesForType(requiredType);
if (candidateNames.length > 1) {
List<String> autowireCandidates = new ArrayList<>(candidateNames.length);
for (String beanName : candidateNames) {
if (!containsBeanDefinition(beanName) || getBeanDefinition(beanName).isAutowireCandidate()) {
autowireCandidates.add(beanName);
}
}
if (!autowireCandidates.isEmpty()) {
candidateNames = StringUtils.toStringArray(autowireCandidates);
}
}
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
}
else if (candidateNames.length > 1) {
Map<String, Object> candidates = new LinkedHashMap<>(candidateNames.length);
for (String beanName : candidateNames) {
if (containsSingleton(beanName) && args == null) {
Object beanInstance = getBean(beanName);
candidates.put(beanName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {
candidates.put(beanName, getType(beanName));
}
}
String candidateName = determinePrimaryCandidate(candidates, requiredType.toClass());
if (candidateName == null) {
candidateName = determineHighestPriorityCandidate(candidates, requiredType.toClass());
}
if (candidateName != null) {
Object beanInstance = candidates.get(candidateName);
if (beanInstance == null || beanInstance instanceof Class) {
beanInstance = getBean(candidateName, requiredType.toClass(), args);
}
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
}
if (!nonUniqueAsNull) {
throw new NoUniqueBeanDefinitionException(requiredType, candidates.keySet());
}
}
return null;
}
}
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
throws BeansException {
return doGetBean(name, requiredType, args, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
Object sharedInstance = getSingleton(beanName);
}
这里再次的给出前面的是否延迟的方法:
@SuppressWarnings("serial")
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
}
Spring IoC循环依赖问题:
前面也有过一个小小的例子,这里我们来完整的进行说明
什么是循环依赖:
循环依赖其实就是循环引用,也就是两个或者两个以上的 Bean 互相持有对方,最终形成闭环,比如A依赖于B,B依赖于C,C⼜依赖于A
注意,这⾥不是函数的循环调用,是对象的相互依赖关系,循环调用其实就是一个死循环,除⾮有终结 条件
Spring中循环依赖场景有:
构造器的循环依赖(构造器注⼊),Field 属性的循环依赖(set注⼊),由于无论是先放入map取出注入还是先注入再放入map的依赖循环问题都是相同的,即对应的注入问题需要对方操作(创建)完毕,而不是单纯的赋值(前面说明的单例就是,所以单例一般没有循环依赖,前提是没有操作构造)
其中,构造器的循环依赖问题⽆法解决,只能拋出 BeanCurrentlyInCreationException 异常(这是因为在构造时,我必然是没有对应的class的,所以如果循环到自己,必然只能报错,因为赋值不了),在解决 属性循环依赖时(spring通常是有顺序的),spring采用的是提前暴露对象的方法
我们可以回到之前的源码中:
populateBean(beanName, mbd, instanceWrapper);
循环依赖处理机制:
单例 bean 构造器参数循环依赖(⽆法解决,我自身都没有,那么你只能创建,又没有,又只能创建,无限循环了),其属性赋值解决了,所以我们不用考虑
prototype 原型 bean循环依赖(⽆法解决),多例的必然不能,因为每次都是新的,是不会考虑赋值的
对于多例原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过setXxx方法产生循环依 赖,Spring都 会直接报错处理(一般也是BeanCurrentlyInCreationException),而单例的只是构造报错,当然BeanCurrentlyInCreationException的错误信息可能存在,但是也可能随着版本的变化而发生改变
我们可以进行测试,对应的配置文件(application.xml):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
">
<bean id="lagouBean" class="com.lagou.edu.LagouBean" scope="prototype">
<property name="itBean" ref="itBean">property>
bean>
<bean id="itBean" class="com.lagou.edu.ItBean" scope="prototype">
<property name="lagouBean" ref="lagouBean">property>
bean>
beans>
测试类:
import com.lagou.edu.LagouBean;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IocTest {
@Test
public void testIoC() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");
Object lagouBean = (Object) applicationContext.getBean(LagouBean.class);
System.out.println(lagouBean);
}
}
在之前的这个地方打上断点(当然,你可以先执行看看错误,看看是否存在BeanCurrentlyInCreationException的错误):
beanFactory.preInstantiateSingletons();
分析如下:
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
}
所以多例的确就是必然操作循环依赖,即不能解决,所以尽量避免多例的循环依赖出现,只要不操作循环不触发即可
单例bean通过setXxx或者@Autowired进行循环依赖(构造报错,但是他的set是可以解决的,虽然他存在,但是已经解决了)
Spring 的循环依赖的理论依据基于 Java 的引用传递,当获得对象的引用时,对象的属性是可以延 后设置的,但是构造器必须是在获取引用之前,所以前面测试循环依赖错误时,基本都是使用引用来完成的,所以实际上循环依赖问题就是单例的问题,因为多例必然报错,所以我们来看看他是如果解决单例的循环依赖的:
Spring(单例)通过setXxx(名称一般我们会认为是setxxx来说明)或者@Autowired方法(考虑到延迟加载,因为其底层是getBean,最终也会考虑setxxx的形式的,因为不是构造,必然是setxxx的形式来解决,或者一些同样功能的来解决,只是名称一般我们会认为是setxxx来说明而已)解决循环依赖其实是通过提前暴露一个ObjectFactory对 象来完成的,简单来说ClassA在调用构造器完成对象初始化之后,在调用ClassA的setClassB方法 之前就把ClassA实例化的对象通过ObjectFactory提前暴露到Spring容器中,这里我们可以观察源码:
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
}
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
@SuppressWarnings("deprecation")
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
return;
}
}
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
}
class BeanDefinitionValueResolver {
@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException(
"Invalid bean name '" + refName + "' in bean reference for " + argName);
}
return refName;
}
else if (value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}
else if (value instanceof BeanDefinition) {
BeanDefinition bd = (BeanDefinition) value;
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
}
else if (value instanceof ManagedArray) {
ManagedArray array = (ManagedArray) value;
Class<?> elementType = array.resolvedElementType;
if (elementType == null) {
String elementTypeName = array.getElementTypeName();
if (StringUtils.hasText(elementTypeName)) {
try {
elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
array.resolvedElementType = elementType;
}
catch (Throwable ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error resolving array type for " + argName, ex);
}
}
else {
elementType = Object.class;
}
}
return resolveManagedArray(argName, (List<?>) value, elementType);
}
else if (value instanceof ManagedList) {
return resolveManagedList(argName, (List<?>) value);
}
else if (value instanceof ManagedSet) {
return resolveManagedSet(argName, (Set<?>) value);
}
else if (value instanceof ManagedMap) {
return resolveManagedMap(argName, (Map<?, ?>) value);
}
else if (value instanceof ManagedProperties) {
Properties original = (Properties) value;
Properties copy = new Properties();
original.forEach((propKey, propValue) -> {
if (propKey instanceof TypedStringValue) {
propKey = evaluate((TypedStringValue) propKey);
}
if (propValue instanceof TypedStringValue) {
propValue = evaluate((TypedStringValue) propValue);
}
if (propKey == null || propValue == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error converting Properties key/value pair for " + argName + ": resolved to null");
}
copy.put(propKey, propValue);
});
return copy;
}
else if (value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue) value;
Object valueObject = evaluate(typedStringValue);
try {
Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
if (resolvedTargetType != null) {
return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
}
else {
return valueObject;
}
}
catch (Throwable ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error converting typed String value for " + argName, ex);
}
}
else if (value instanceof NullBean) {
return null;
}
else {
return evaluate(value);
}
}
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
}
if (bean instanceof NullBean) {
bean = null;
}
return bean;
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
}
所以可以发现,在填充时,的确考虑了对应的bean的三级缓存,所以单例是解决循环依赖的,即我们只需要不主动操作多例的循环,那么循环依赖的问题我们基本不会出现的
我们可以继续调试,当第二个bean操作了对应的bean = this.beanFactory.getBean(refName);时,可以在这里发现原因:
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
}
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
}
由于拿取了三级缓存的数据,所以对应的doGetBean方法直接返回该数据,完成了当前bean的设置,放入一级缓存,清空其他缓存,然后返回,也使得对应调用的进行了数据的设置,也完成了对应的bean设置,然后也放入一级缓存,至此循环依赖流程说明完毕,即单例也的确解决了循环依赖,很明显,在设置的过程中三级缓存解决循环依赖,并且也顺序放入一级缓存,使得我们通过名称得到map时节省时间,所以真正解决循环依赖的是三级缓存,删除的三级缓存并不影响循环依赖的解决,因为是方法里面调用方法,只要一个完成,后续都会完成的,所以只要三级缓存完成了他的一次作用就行了(三级缓存到一级缓存中间处理了二级缓存了,这里了解即可)
一般来说,Spring是默认允许循环依赖的,所以就会默认操作三级缓存,否则是不会的,那么就会出现循环的问题(具体设置可以百度,可能随着时间的推移,是不允许的,或者这个不允许通常只是建立在错误的情况下是不允许的,即错误导致的不会出现循环依赖,称为不允许)
Spring AOP 应用:
在前面我们基本说明了IOC相关的源码,现在来说Spring两个重要概念中IOC和AOP的AOP
AOP本质:在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、⽇志代 码、事务控制代码、性能监控代码
AOP 相关术语:
业务主线:
在讲解AOP术语之前,我们先来看一下下面这两张图:
上图描述的就是未采用AOP思想设计的程序,当我们红⾊框中圈定的方法时,会带来大量的重复劳动,程序中充斥着大量的重复代码,使我们程序的独立性很差,而下图中是采用了AOP思想设计的程序,它 把红框部分的代码抽取出来的同时,运用动态代理技术,在运行期对需要使用的业务逻辑方法进行增 强
在看下面这个图时,建议回顾第65章博客:
当然,学习对应的第65章博客的内容就知道了,学习后,我们继续看后面:
首先给出一个环境:
对应的pom.xml文件:
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.8.13version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.1.5.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
对应的MyAdvice类:
package com.lagou.advice;
public class MyAdvice {
public void before() {
System.out.println("前置通知执行了");
}
public void after() {
System.out.println("后置通知执行了");
}
public void aftert() {
System.out.println("最终通知执行了");
}
}
对应的AccountService接口:
package com.lagou.service;
public interface AccountService {
public void transfer();
}
对应的AccountServiceImpl实现类:
package com.lagou.service.impl;
import com.lagou.service.AccountService;
public class AccountServiceImpl implements AccountService {
@Override
public void transfer() {
System.out.println("转账方法执行了");
}
}
对应的AccountServiceTest类:
package com.lagou.test;
import com.lagou.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ap.xml")
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testTransfer() {
accountService.transfer();
}
}
对应的配置文件ap.xml:
<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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="accountService" class="com.lagou.service.impl.AccountServiceImpl">bean>
<bean id="myAdvice" class="com.lagou.advice.MyAdvice">bean>
<aop:config>
<aop:aspect ref="myAdvice" id="myAdvice">
<aop:before method="before"
pointcut="execution(void
com.lagou.service.impl.AccountServiceImpl.transfer())"/>
<aop:after-returning method="after"
pointcut="execution(void
com.lagou.service.impl.AccountServiceImpl.transfer())"/>
<aop:after method="aftert"
pointcut="execution(void
com.lagou.service.impl.AccountServiceImpl.transfer())"/>
aop:aspect>
aop:config>
beans>
执行一下,出现结果如下:
我们可以这样:
修改配置文件:
<aop:config>
<aop:aspect ref="myAdvice" id="myAdvice">
<aop:before method="before"
pointcut="execution(void
com.lagou.service.impl.AccountServiceImpl.transfer(java.lang.Integer))"/>
aop:aspect>
aop:config>
对应修改如下:
public interface AccountService {
public void transfer(Integer i);
}
public class AccountServiceImpl implements AccountService {
@Override
public void transfer(Integer i) {
System.out.println("转账方法执行了");
}
}
@Test
public void testTransfer() {
accountService.transfer(1);
}
最终的修改:
public void before(JoinPoint joinPoint) {
System.out.println(joinPoint);
System.out.println(joinPoint.getArgs());
for(Object o : joinPoint.getArgs()){
System.out.println(o);
}
System.out.println("前置通知执行了");
}
即对应的joinPoint.getArgs()保存了被切入点的参数列表的值,若是之前,那么什么都没有的(对与环绕通知,对应的ProceedingJoinPoint也有该方法,并且也可以作为参数传递,但是对应的proceed = pjp.proceed()可以不写,默认是对应的参数,写上,那么参数变成你写的,所以如果你操作ProceedingJoinPoint的getArgs()方法,那么不变,若你操作new Object[]{3},那么对应的参数变成了3,这里注意即可,可以选中试一下,前面你复习过的话,应该知道怎么操作,并且对应的还可以不执行业务逻辑,即ProceedingJoinPoint的proceed方法可以不执行)
也要记得,对应是使用代理的,所以如果你不执行对应的方法,那么就拦截不了,自然没有什么通知(增强,包括环绕通知)
我们还存在这样的操作:
<aop:aspect ref="myAdvice">
<aop:after-returning method="after" returning="aa"
pointcut="execution(int
com.lagou.service.impl.AccountServiceImpl.transfer(int))"/>
aop:aspect>
public int transfer(int i);
@Override
public int transfer(int i) {
System.out.println(i);
System.out.println("转账方法执行了");
return 9;
}
@Test
public void testTransfer() {
accountService.transfer(8);
}
public void after(Object aa) {
System.out.println(aa);
System.out.println("后置通知执行了");
}
我们也可以通过注解来解决(大改变):
对应的MyAdvice类:
package com.lagou.advice;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
AccountService接口及其实现类:
package com.lagou.service;
public interface AccountService {
public void transfer();
}
package com.lagou.service.impl;
import com.lagou.service.AccountService;
import org.springframework.stereotype.Component;
@Component
public class AccountServiceImpl implements AccountService {
@Override
public void transfer() {
System.out.println("转账方法执行了");
}
}
测试类AccountServiceTest:
package com.lagou.test;
import com.lagou.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ap.xml")
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testTransfer() {
accountService.transfer();
}
}
对与的配置文件:
<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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.lagou">context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true">aop:aspectj-autoproxy>
<aop:aspectj-autoproxy proxy-target-class="false">aop:aspectj-autoproxy>
beans>
执行看看是否有结果,如果有,那么操作成功,现在,我们继续修改MyAdvice:
package com.lagou.advice;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
给出MyAdvice1类:
package com.lagou.advice;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
public class MyAdvice1 {
@Pointcut("execution(* com.lagou.service.impl.AccountServiceImpl.transfer())")
public void myPoint() {
}
}
继续测试,如果有结果,那么操作成功,如果说之前的参数,我们可以通过改变execution来添加参数,那么返回值怎么进行设置呢,根据参数和返回值都只是逻辑上的操作,参数自然是目标方法的改变,而返回值,自然是目标方法之后的改变,自然就是后置通知,所以当操作如下时(MyAdvice的改变):
package com.lagou.advice;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
我们同样的需要到这里进行修改:
public interface AccountService {
public int transfer();
}
@Component
public class AccountServiceImpl implements AccountService {
@Override
public int transfer() {
System.out.println("转账方法执行了");
return 10;
}
}
执行,看看结果,若有数据说明操作完毕,那么若存在环绕通知的情况下,对应的返回值一般什么时候进行返回呢,答:在环绕通知自身的最终通知之后,以及被环绕通知或者注解改变顺序使得原来后置通知在最终通知之后的之前,比如:
我们可以使用完全的注解,在lagou包下创建config包,并创建SpringConfig类:
package com.lagou.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.lagou")
@EnableAspectJAutoProxy
public class SpringConfig {
}
然后改变测试类AccountServiceTest:
package com.lagou.test;
import com.lagou.config.SpringConfig;
import com.lagou.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testTransfer() {
accountService.transfer();
}
}
这样就是纯注解了,这里是必须需要先操作配置类的,只是将配置类的读取变成读取xml,所以在SpringBoot中同样也是如此(操作配置类)
由于博客字数限制,其他内容,请到下一篇博客(108章博客)去看