解读Spring定义Bean的两种方式:<bean>和@Bean
作者:恐龙弟旺仔 发布时间:2023-01-25 23:37:51
前言
Spring中最重要的概念IOC和AOP,实际围绕的就是Bean的生成与使用。
什么叫做Bean呢?我们可以理解成对象,每一个你想交给Spring去托管的对象都可以称之为Bean。
今天通过Spring官方文档来了解下,如何生成bean,如何使用呢?
1.通过XML的方式来生成一个bean
最简单也是最原始的一种方式,通过XML来定义一个bean,我们来看下其过程
1)创建entity,命名为Student
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
private static final long serialVersionUID = -2088281526481179972L;
private int id;
private String name;
private int age;
}
2)在beans.xml中定义Student
<!-- 1.空值的student -->
<bean id="studentNoValue" class="domain.Student"/>
<!-- 2.带值的student -->
<bean id="student" class="domain.Student">
<property name="id" value="11"/>
<property name="age" value="22"/>
<property name="name" value="jack"/>
</bean>
<!-- 3.全参构造:使用成员变量名称对应 -->
<bean id="studentConstruct" class="domain.Student">
<constructor-arg name="age" value="22"></constructor-arg>
<constructor-arg name="id" value="11"></constructor-arg>
<constructor-arg name="name" value="jack"></constructor-arg>
</bean>
<!-- 4.全参构造:使用成员变量index对应 -->
<bean id="studentConstruct2" class="domain.Student">
<constructor-arg index="0" value="11"></constructor-arg>
<constructor-arg index="1" value="jack"></constructor-arg>
<constructor-arg index="2" value="22"></constructor-arg>
</bean>
<!-- 5.全参构造:使用成员变量类型对应 -->
<bean id="studentConstruct3" class="domain.Student">
<constructor-arg type="int" value="11"></constructor-arg>
<constructor-arg type="java.lang.String" value="jack"></constructor-arg>
<constructor-arg type="int" value="22"></constructor-arg>
</bean>
总结:可以看到,创建bean的方式多种多样,我们可以通过属性来赋值<property>,也可以通过构造参数来赋值<constructor>,关于构造赋值以上展示了三种方式,我们可以根据自己的需求来选择对应的方式。
3)测试bean
public class ApplicationContextTest {
@Test
public void testXml(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Student studentNoValue = (Student) applicationContext.getBean("studentNoValue");
Student studentFullValue = (Student) applicationContext.getBean("studentFullValue");
System.out.println(studentNoValue);
System.out.println(studentFullValue);
Student studentConstruct1 = (Student) applicationContext.getBean("studentConstruct");
Student studentConstruct2 = (Student) applicationContext.getBean("studentConstruct2");
Student studentConstruct3 = (Student) applicationContext.getBean("studentConstruct3");
System.out.println(studentConstruct1);
System.out.println(studentConstruct2);
System.out.println(studentConstruct3);
Book bookChinese = (Book) applicationContext.getBean("bookChinese");
System.out.println(bookChinese);
}
}
// res:
Student(id=0, name=null, age=0)
Student(id=11, name=jack, age=22)
Student(id=11, name=jack, age=22)
Student(id=11, name=jack, age=22)
Student(id=11, name=jack, age=22)
2.<bean>标签深入了解
我们刚才介绍了最基本的Bean使用方式,大家会发现<bean>标签还有其他的属性,比如name/scope/lazy-init/init-method/...等,这些是做什么用的呢?我们在实际的工作中怎么使用呢?
1)name属性
在介绍name属性之前,我们先来看下ApplicationContext.getBean()的两种方式
* ApplicationContext.getBean(String name)
* ApplicationContext.getBean(Class<T> requiredType)
第一种方式的这个name是什么呢?我们应该如何定义,又该如何使用呢?
// 上文示例中,我们只是指定了Bean的id和class,如下所示
<bean id="studentNoValue" class="domain.Student" />
// 具体获取bean的方式如下:
Student studentNoValue = (Student) applicationContext.getBean("studentNoValue");
// 可以看到,在没有指定bean的name属性的时候,默认使用id来获取bean,当做name使用
// 如果我们不想根据id获取,那就需要主动指定bean的name属性,如下所示:
<bean id="studentNoValue" class="domain.Student" name="stuName"/>
// 这样在获取的时候,就需要使用指定的名称来获取,再根据id来获取的时候就会报错了
Student studentNoValue = (Student) applicationContext.getBean("stuName");
* 根据Class来获取这种方式很好理解,这个不关心你定义的id或者name是什么,使用如下:
Student studentNoValue = (Student) applicationContext.getBean(Student.class);
2)scope属性
可以看到,在使用scope属性的时候,提示有两种输入值,分别是singleton/prototype
这个就代表了Spring-Bean的两种创建模式,单例模式和原型模式
* Spring默认使用单例模式来创建Bean,通过ApplicationContext所获得的bean都是同一个bean(在beanName相同的情况下),我们可以来验证下
Student studentNoValue = (Student) applicationContext.getBean("stuName");
Student studentNoValue2 = (Student) applicationContext.getBean("stuName");
System.out.println(studentNoValue == studentNoValue2);// true
可以看到的是结果输入为true,从工厂类中两次获取的stuName是同一个对象。
* 下面来验证下原型模式
原型模式:每次获取的bean都为一个新的对象
// 修改beans.xml中studentNoValue的scope为prototype
<bean id="studentNoValue" class="domain.Student" name="stuName" scope="prototype"/>
// 然后执行上面的测试代码
Student studentNoValue = (Student) applicationContext.getBean("stuName");
Student studentNoValue2 = (Student) applicationContext.getBean("stuName");
System.out.println(studentNoValue == studentNoValue2);// false
可以看到,输出结果为false,原型模式下从工厂类两次获取的stuName不是同一个对象。
3)init-method和destroy-method方法
见名知意,init-method应该是初始化方法的意思,destroy-method应该是销毁方法的意思。那怎么使用呢?
// 在Student.java中添加init()方法和destroy()方法
public void init(){
System.out.println("student init...");
}
public void destroy(){
System.out.println("student destroy...");
}
// 在beans.xml中studentNoValue的bean上添加 init-method和destroy-method
<bean id="studentNoValue" class="domain.Student" name="stuName" init-method="init" destroy-method="destroy"/>
// 测试方法如下:
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Student studentNoValue = (Student) applicationContext.getBean("stuName");
applicationContext.close();
// 执行结果:
student init...
student destroy...
总结:在获取bean的时候init()方法被执行,在容器被销毁的时候,执行了destroy()方法
根据这个,我们可以在初始化bean和销毁bean的时候做点什么,比如关闭连接,保存记录之类的操作。
延伸:那么初始化init()方法在构造方法之前调用,还是之后调用呢?读者可以自行验证下
总结:还有一些其他属性,笔者就不再一一验证了,下面说一下通过JavaConfig的方法来实现bean的定义。
3.JavaConfig方式的bean定义
JavaConfig是Spring4.x推荐的配置方式,可以完全替代XML的方式定义。
1)如何定义一个Bean
// 创建一个类,命名为SpringConfiguration
@Configuration
public class SpringConfiguration {
@Bean
public Student student(){
return new Student(11,"jack",22);
}
}
// 使用bean
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(SpringConfiguration.class);
Student student = (Student) applicationContext.getBean("student")
System.out.println(student);
// res:
Student(id=11, name=jack, age=22)
相对于XML的使用方式而言,JavaConfig的使用方式基本是同步的
* @Configuration等同于<beans></beans>
* @Bean等同于<bean></bean>
* 通过AnnotationConfigApplicationContext来加载JavaConfig
* 方法名student()就等同于<bean>中的id,默认方法名就是beanName
2)@Bean的其他参数
* name属性等同于<bean>的name
* initMethod属性等同于<bean>的init-method
* destroyMethod属性等同于<bean>的destroy-method
* scope这个比较奇怪,不属于@Bean的参数,这是一个单独的注解,使用方式如下
@Bean(name = "stu",autowire = Autowire.BY_TYPE)
@Scope(value = "singleton")
public Student student(){
return new Student(11,"jack",22);
}
来源:https://kldwzz.blog.csdn.net/article/details/89761303
猜你喜欢
- 本文实例为大家分享了java利用数组随机抽取幸运观众的具体代码,供大家参考,具体内容如下思想:首先将所有观众姓名生成数组,然后获取数组元素的
- 开发 Web 应用的思路实现一个简单的 JSP/Servlet。搭建创建 Web 应用工程的环境。创建 Web 应用工程。Web 应用工程的
- java swing GUI窗口美化一般我们写出的窗口是这个样子的,文本框和按钮都不是太美观,如果按钮是原色的就更难看了。今天发现了一个更加
- 单例模式用于保证在程序的运行期间某个类有且仅有一个实例。其优势在于尽可能解决系统资源。通过修改构造方法的访问权限就可以实现单例模式。代码如下
- throw抛出异常的方式比较直接:if(age < 0){throw new MyException("年龄不能为负数!&q
- 文件下载是一个软件开发中的常见需求。本文从最简单的下载方式开始步步递进,讲述了文件下载过程中的常见问题并给出了解决方案。并展示了如何使用多线
- 概述在JDK 1.8里,可以使用如下代码获取List元素对象中某个属性的列表。package test;import java.util.A
- 本文实例为大家分享了Java NIO实现聊天功能的具体代码,供大家参考,具体内容如下server code : package c
- 本文实例为大家分享了Android自定义View之组合控件,仿电商app顶部栏的相关代码,供大家参考,具体内容如下效果图:分析:左右两边可以
- 概述递归:指在当前方法内调用自己的这种现象。递归的分类:递归分为两种,直接递归和间接递归。直接递归称为方法自身调用自己。间接递归可以A方法调
- 加密配置文件的SQL账号密码一般项目的配置文件里的信息都是明文的,导致有时候比较敏感的信息也直接暴露得超级明显,比如SQL的链接 账号 密码
- CountDownLatch在日常开发中经常会遇到需要在主线程中开启多个线程去并行执行任务,并且主线程需要等待所有子线程执行完毕后再进行汇总
- 实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet 而言,系统采用 Hash 算法决定集合元素的存储位置,
- * 是许多框架底层实现的基础,比如Spirng的AOP等,其实弄清楚了 * 的实现原理,它就没那么神奇了,下面就来通过案例和分析JDK
- 1.editplus1.1 官方下载https://www.editplus.com/官方下载最新的64位2 .解压就可以使用2.1 vsc
- 本文实例为大家分享了Java实现员工管理系统的具体代码,供大家参考,具体内容如下本系统主要练习到的相关内容: 1、 流程控制语句 2、 类、
- activity A和BA 获取数据的activity B返回数据的activity点击A上的按钮,在A的textview上显示
- 表关联上一篇介绍了JPA的简单使用,这一篇介绍JPA在表关联上的使用一对一配置参数JPA对于数据实体一对一映射使用的是@OneToOne注解
- Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spri
- spring Boot 使用事务非常简单,首先使用注解 @EnableTransactionManagement 开启事务支持后,然后在访问