spring中产生bean的几种方式
Posted Hide on jdk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring中产生bean的几种方式相关的知识,希望对你有一定的参考价值。
@Bean
@Import
MyImportSelector implements ImportSelector
MyImportBeanDefinitionRegistarimplements ImportBeanDefinitionRegistrar
FactoryBean
这里着重讲解FactoryBean
如何判断当前bean是否是FactoryBean
org.springframework.beans.factory.support.AbstractBeanFactory#isFactoryBean(java.lang.String)
org.springframework.beans.factory.support.AbstractBeanFactory#isFactoryBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition)
查看mbd中的属性即可。
手动拼接一个&走生命周期
注意上图doGetBean的时候会把beanname里面的&去掉,包括多个&的beanname也会把多个&去掉。
如果该bean是factorybean的话,那么第一次加上&的话走了生命周期,单例池就会有该bean,如果是SmartFactoryBean的话第二次执行就会走下面标红的代码来处理getObject逻辑。
看下如何处理?
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance
先去缓存中拿:由于是factorybean是不会变动的,所以放入缓存提高查询效率
缓存中第一次肯定拿不到,继续执行标红代码
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean
放入缓存。
spring初识--bean的几种注册方式
spring彻底改变了java世界观。spring解决了java 对象管理问题,今天我们来看看spring创建对象的方式有哪些至今还不知道的吧
注册bean的几种方式(IOC)
BeanDefinition
- 我们查看类图可以看出,
BeanDefinitionRegistry
下有三个实现类。spring为我们提供了一个默认的BeanDefinition
注册工厂DefaultListableFactory
。 为什么说他是默认的不仅仅是因为名字里出现了Default字样。而是在AnnotationConfigApplicationContext
中默认使用的就是DefaultListableFactory。在注解式开发汇总AnnotationConfigApplicationContext
上下文是经常使用的。他也可以理解成spring容器。
配置类Config
- 相信大家都是用过springboot。在springboot中首先需要一个启动类。这个启动类上会添加各种各样的注解进行修饰。其实他就是一个配置的入口。相当于spring中的xml配置文件。
- 为了演示我们这里也需要一个这样的配置类。告诉spring哪些类他需要进行装载解析。
@ComponentScan(value = "com.zxhtom.cloud.order.spring")
public class Config
- Config的作用就是告诉spring去扫描
com.zxhtom.cloud.order.spring
包下带有spring注解的类及配置类
生成bean
- 相信大家对
@Bean
、@Component
、@Service
这些注解都不陌生。这些都是spring bean的注解。但是这些注解的背后又是什么呢。对!就是本章节的主题BeanDefinition
。 spring的bean的注册都是通过它来完成的。
//首先获取容器上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
//生成java类对应的BeanDefinitionBuilder
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(Student.class);
//将BeanDefinition注册到该spring容器上
context.registerBeanDefinition("student",builder.getBeanDefinition());
//尝试获取
Object orderController = context.getBean("student");
System.out.println(orderController);
-
上面简单几行就完成了springbean的注册。在
AnnotationConfigApplicationContext
中,我们看到他是继承了GenericApplicationContext
这个类的。而这个类中默认的是上面我们提到的DefaultListableFactory
-
这也是我们在开始放置的一张图。到这里我们知道BeanDefinition是spring注册bean的元素。而
BeanDefinitionRegistry
是注册真正的工作者。他负责解析BeanDefinition
将对应的Java对象转换成spring的bean。这中间还有很多很多的细节处理。这里我们不做展开啦。
FactoryBean
-
FactoryBean
是一个接口,在java8中我们只需要实现getObject
、getObjectType
两个方法。前者是生成对象后者是返回对象Class对象。 -
下面我们通过
FactoryBean
来创建一个springbean .
@Data
public class User
private String name;
- ①首先我们编写一个普通的Java类User 。不要添加spring注册bean的注解
public class UserFactoryBean implements FactoryBean<User>
@Override
public User getObject() throws Exception
User user = new User();
user.setName("hello");
return user;
@Override
public Class<?> getObjectType()
return User.class;
- ②然后在编写一个实现了
FactoryBean
接口的实现类。在getObject方法中我们构造一个User对象并返回。
public class BeanTest
public static void main(String[] args)
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(UserFactoryBean.class);
context.refresh();
context.registerBeanDefinition("user", builder.getBeanDefinition());
System.out.println("获取user:"+context.getBean("user"));
System.out.println("获取userFactoryBean:"+context.getBean("&user"));
-
③最后我们构建一个
UserFactoryBean
对应的BeanDefinition
对象。值得注意的是UserFactoryBean的BeanDefinition会向spring注册两个对象到spring容器中。一个是getObject方法中的对象。另外一个就是UserFactoryBean
自己本身。 -
在spring容器中是通过KV形式保存对象信息的,两个对象是不可能对应同一个key的。上面注册进来的名称是user 。
key | 对象 |
---|---|
user | User对象 |
&user | UserFactoryBean对象 |
FactoryBean
作用就是将负责的bean生成过程进行代码话。 比如上面是构建一个User对象注册到spring容器。这种需求我们直接在User类上添加@Component
并在Springboot启动类上添加扫描路径就可以了。- 但是如果User对象中的name在启动是需要将当前时间赋值给name, 这种需求我们就不好通过spring提供的注解配置了。但是通过
FactoryBean
就可以很好的解决了。因为我们通过代码很容器就获取到时间并进行赋值。 FactoryBean
在spring中的地位也是很高的。在mybatis框架中如何将Mapper接口注册到spring容器就是利用他的功能。因为spring中是无法注册接口的。mybatis将接口生成代理类注册到spring容器。在执行这些代理类的时候在根据Mapper对象的xml里的sql进行SqlSession执行sql进行数据的解析。
Supplier
- 在
GenericApplicationContext
类中我们发现registryBean
方法中有个重载的方法需要参数Class、Supplier、BeanDefinitionCustomer。
public static void main(String[] args)
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
context.registerBean("user", User.class);
User user = (User) context.getBean("user");
System.out.println(user.getName());
- 还是上面的需求,我需要注册是将当前时间赋值给User#name属性。这个时候常规操作是没法满足需求的。这个时候除了上面提到的
FactoryBean
以外,我们还可以通过Supplier来初始化。
public static void main(String[] args)
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
context.registerBean(User.class, new Supplier<User>()
@Override
public User get()
User user = new User();
user.setName(new Date().toString());
return user;
, new BeanDefinitionCustomizer()
@Override
public void customize(BeanDefinition bd)
bd.setPrimary(true);
System.out.println(bd);
);
User user = (User) context.getBean("user");
System.out.println(user.getName());
- 上述代码实现了User对象属性初始化注册。并对BeanDefinition进行加强更新。在Spring中Customizer往往代码封装的意思。
BeanDefinitionCustomizer
就是对BeanDefinition
对象的封装方便对他们进行二次操作。
spring AOP
- AOP全称Aspect Oriented Programming的缩写。在spring中我们已经习惯了面向切面编程了。切面真的帮助我们实现了很多帮助。他将我们重复性的工作进行抽离,是的我们整体的业务不再线性的编程了。最终我们在开发过程就会变成模块–>aop–>模块
概念
-
在aop中我们需要了解到几个专有名词
-
Aspect : 申明切面
-
Joint point : 表示连接点。对异常处理
-
Pointcut : 切点。定义拦截点。由点生面
-
Advice : 在切点上进行增强,对执行点进行包装
-
Target : 代理对象的真实对象
-
Weaving: 将Aspect连接起来
spring容器的认识
- 上面我们演示的spring的两大特性。IOC+AOP。 其中IOC就是通过反射将java对象注册到容器中。那么这个容器到底是什么个东西。这里我们就简单的理解成KV 。 内部其实就是一个Map. key就是java对象在容器中的beanName。value就是java对象本身.
授人以鱼不如授人以渔,Spring的强大相信做过Java开发的都是知道。今天我们开始Spring相关课程的第一话–纵观全局
今后我们也是从这个五个方面进行入手,由于探讨框架本身存在很多未知数,里面的总结也肯定是参考别的文献的。个人总结
Spring结构
Core Container
Spring中的Core Container(核心容器)包含有Core、Beans、Context和Expression Language模块。Core和Beans模块是框架的基础部分,提供IoC(反转控制)和依赖注入特性。这里的基础概念是BeanFactory,它对Factory模式的金典实现来消除对程序性单利模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。
Core
core模块主要包含Spring框架基本的核心工具类,Spring的其他组件都需要使用这个包里的类。
core相当于是底层文件,任何spring的产品都是建立在core上的。
Beans
Beans在Core的基础上进行了功能的扩展它包含访问配置文件,创建和管理bean以及进行控制反转、依赖注入操作相关的所有类。
Beans相当于是功能性的提供。所有的spring项目都用到这个功能。这里引入了Spring重大特性之一的依赖注入(控制反转)
Context
Context 模块构建于 Core 和 Beans 模块基础之上,提供了一种类似于刑DI 注册器的框
架式的对象访问方法 。 Context 模块继承了 Beans 的特性,为 Spring 核心提供了大量
扩展,添加了对国际化(例如资源绑定)、事件传播、资源加载和对 Co ntext 的 透明创
建的支持 。 Context 模块同时也支持 J2EE 的一些特性, 171) :Ji.口 EJB 、几仪和基础的远程
处理 。 ApplicationContext 接口是 Context 模块的关键 。
Expression Language模块提供了一个强大的表达式语言用于在运行时查询和操作对象。
Expression Language 模块提供了强大的表达式语言,用于在运行时查询和操纵对象 。
它是 JSP 2.1 规范中定义的 unifed expression language 的扩展 。 该语言支持设直/获取属
性的值,属性的分配,方法的调用,访问数组上下文(
accessiong the context of arrays )、
容器和索引器、逻辑和算术运算符、命名变量以及从 S prit屯的 IoC 容器中根据名称检
索对象 。 它也支持 list 投影、选择和一般的 list 聚合
Data Access/Integration
Data Access/Integration 层包含而BC 、 ORM 、 OXM 、几础和 Transaction 模块 。
- JDBC模块提供了一个JDBC抽象层,它可以消除冗长的JDBC编码和解析数据库厂商特有的错误代码。 这个模块包含了Spring对JDBC数据访问进行封装的所有类。
- ORM模块为流行的对象-关系映射API,如JPA、JDO、Hibernate、Mybatis.提供了一个交互层。利用ORM封装包,可以混合使用所有Springboot提供的特性进行OR映射
Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO 、Hibernate 和 iBatisSQL Map 。 所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构 - OXM 模块提供了一个对 ObjecνXML 映射实现的抽象层, Object/XML 映射实现包括JAXB 、 Castor 、 XMLBeans 、 JiBX 和 XStrearn 。。
- JMS ( Java Messaging Service )模块主要包含了 一些制造和消 费消息的特性 。
- Transaction 模块支持编程和声明性的事务 管理,这些事务类必须实现特定的接 口,并且对所有的 POJO 都适用 。
Web
Web上下文模块建立在应用程序上下文模块之上。为基于Web的应用程序提供了上下文。所以Spring框架支持与Jakarta Struts集成。Web模块还简化了处理大部分请求以及讲请求参数绑定到域对象工作,Web层包含了Web,Servlet、Struts、Porlet模块。
- Web模块:童工基础的面向web的集成特性。多文件上传、使用listeners初始化IOC容器、容器上下文。还包括Spring远程支持中Web的相关部分。
- Servlet模块: 该模块包含 Spring 的 model-view-controller ( MVC)实现 。 Spring 的 MVC 框架使得模型范围内的代码和 web forms 之间能够清楚地分离开
来,并与 Spring 框架的其他特性集成在一起 - Struts模块:该模块提供了对Struts支持,是的类在Springboot容器中能够与一个典型的Struts web 层集成在一起,spring3.0之后已被抛弃
- Porlet模块: 提供了用于Portlet环境和Web——servlet模块的Mvc的实现
Aop
AOP 模块提供了 一个符合 AOP 联盟标准的面向切面编程的实现,它让你可以定义例如方
法拦截器和切点,从而将逻辑代码分开,降低它们之间的调合性 。 利用 source-level 的元数据
功能,还可以将各种行为信息合并到你的代码中,这有点像 .Net 技术中的 attribute 概念 。
通过配置管理特性, SpringAOP 模块直接将面向切面的编程功能集成到了 Spring 框架中,
所以可以很容易地使 Spring 框架管理的任何对象支持 AOP 。 Spring AOP 模块为基于 Spring 的
应用程序中的对象提供了事务管理服务 。 通过使用 SpringAOP ,不用依赖 EJB 组件,就可以将
声 明性事务管理集成到应用程序中 。
Aspects 模块提供了对 AspectJ 的集成支持 。
。
Instrumentation 模块提供了 class instrumentation 支持和 classloader 实现, 使得可以在特
定的应用服务器上使用 。
Test
Test模块就是在容器内进行单元测试。没啥好说的。
总结
- spring是个框架,但是现在spring已经不仅仅是框架了。我们可以把spring理解成一个生态。
- 在spring基础上已经衍生出脚手架springboot 。 还有在微服务上的springcloud
- 而在springcloud中有衍生出很多的组件。大多都是借鉴了netflix 。 比如说eureka、 zuul 等 。 其中zuul已被springcloud gateway取代
- 因为spring的设计优秀已经和mybatis、redis、rabbitmq这些都是完美的整合了。
- 本章主要是介绍spring . 后面也会继续更新springcloud专题。 因为在cloud中发现对spring的基础要求还是很高的。
- 这个五一先放放cloud 。 来个spring爽爽 。 cloud五一后再见
务上的springcloud - 而在springcloud中有衍生出很多的组件。大多都是借鉴了netflix 。 比如说eureka、 zuul 等 。 其中zuul已被springcloud gateway取代
- 因为spring的设计优秀已经和mybatis、redis、rabbitmq这些都是完美的整合了。
- 本章主要是介绍spring . 后面也会继续更新springcloud专题。 因为在cloud中发现对spring的基础要求还是很高的。
- 这个五一先放放cloud 。 来个spring爽爽 。 cloud五一后再见
以上是关于spring中产生bean的几种方式的主要内容,如果未能解决你的问题,请参考以下文章