1、获取bean实例的三种方式
UTF-8
4.3.18.RELEASE
1.16.18
4.11
org.springframework
spring-beans
${spring.version}
org.springframework
spring-core
${spring.version}
org.springframework
spring-context
${spring.version}
org.springframework
spring-expression
${spring.version}
- id 属性:被spring容器进行管理的实例的 唯一标识,整个容器中,只能是唯一的(不可重复);
- class属性:指定创建当前实例对象的类型(全类名),spring底层是使用的 反射机制 ,根据指定的目标类型,创建目标实例(必须有 空参构造)
* - name:指定对象的属性名
- value: 给属性赋值
@Test
public void testSpringPrimer(){
//1.创建spring的核心容器对象(引用上下文对象),解析spring的核心配置文件,将文件中的bean标签进行实例化(创建对象并赋值)
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2. 写法一: 从容器中获取实例对象,根据核心配置文件中,配置的bean标签的id属性值
// 不足:强制转化,容易出现转换错误
User userOne = (User) context.getBean("userOne");
userOne.sayHello();
//对比以前创建对象的写法(对象必须手动new创建,并手动赋值)
User userOld = new User();
userOld.setNickName("kh96_old");
userOld.sayHello();
}
通过id属性,获取实例对象后 需要强制转换,容易出现 强制转化错误;
//写法二:从容器中获取实例对象,根据核心配置文件中,配置的bean标签的class属性指定的目标类型
User userTwo = context.getBean(User.class);
userTwo.sayHello();
不足:如果 存在同类型的多个实例,会 报异常;
当用多个同类型的实例:
...
...
User userTwo = context.getBean(User.class);
会发生异常:
NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.kgc.spring.bean.User’ available: expected single matching bean but found 2: userOne,userTwo
主要原因是由于 只用class属性去获取实例,但是有多个相同类型的实例,所以 无法确定你要获取的是哪一个;
//写法三:从容器中获取实例对象,根据配置文件中,配置的bean标签的id属性值和class属性指定的目标类型
User userTwoThree = context.getBean("userTwo", User.class);
能够 确定唯一实例,推荐使用;
配置文件中的 id必须是唯一的;
如果id不唯一:两个id一样的实例
...
...
报错:
BeanDefinitionParsingException: Configuration problem: Bean name ‘userOne’ is already used in this
提示 id 为 userOne 的实例已经存在;
当 初始化spring的容器对象时,会 将核心配置文件中所有的bean实例化,不是使用哪个,创建哪个;
2、DI
IOC(控制反转是一种思想),DI是IOC的一种实现方式;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//用户昵称
//普通参数
private String nickName;
//私家车
//实体参数
private Car car;
//喜欢的书
//数组参数
private String[] books;
//爱好
//list集合参数
private List hobbies;
//喜欢的游戏
//set 集合
private Set games;
//卡包
//map参数
private Map cards;
//在校信息
//properties参数
private Properties info;
//是否有女朋友 (主要是演示赋值为null,其他类型都可以)
//空参数注入
private Boolean wife;
}
...
红楼梦
水浒传
三国演义
西游记
跑步
尤克里里
敲代码
唱歌
跳舞
喝酒
123456
男
化羽
...
@Test
public void testPramsDI(){
User user01 = context.getBean("user01", User.class);
//输入对象详情
System.out.println(user01);
}
输出结果:
User(
nickName=小气鬼,
car=Car(brand=Bmw325, factory=华晨, price=300000.0),
books=[红楼梦, 水浒传, 三国演义, 西游记],
hobbies=[跑步, 尤克里里, 敲代码],
games=[唱歌, 跳舞, 喝酒],
cards={身份证=1212121212121212, 银行卡=1111111111111111},
info={学号=1913001072, 性别=男, 姓名=化羽},
wife=null
)
@Test
public void testSpringDIConstructor(){
Car carTwo = context.getBean("carTwo", Car.class);
//输出对象详情
System.out.println(carTwo);
}
@Test
public void testSpringDIConstructor2(){
Car carTwo = context.getBean("carThree", Car.class);
//输入对象详情
System.out.println(carTwo);
}
自定义实体工厂bean ,必须 实现FactoryBean接口;
普通bean 与 工厂bean 的区别:
- 普通 bean:在 配置文件中定义 bean 类型 就是 返回类型
- 工厂 bean:在 配置文件定义 bean 类型 和 返回类型 不一样
@Data
@ToString
public class Car {
/*
品牌
*/
private String brand;
/*
厂商
*/
private String factory;
/*
价格
*/
private Double price;
}
- 在 spring容器初始化时,创建 当前工厂bean的实例对象,但是 真实返回的 不是当前类的实例对象, 而是当前类的实例对象返回的目标实例对象(自定义);
- 作用:可以 在程序中,实现 自定义创建实例(还可以增加业务逻辑处理),放入容器;
- 存在的原因:spring框架 对外开放了一个入口,可以让其他的 开发人员参与到spring底层创建bean的实例过程中去, 给整合其他框架使用的,比如mybatis;
public class CarFactoryBean implements FactoryBean {
@Override
public Car getObject() throws Exception {
System.out.println("通过CarFactoryBean的实例对象的getObject方法:返回一个自定义的car的实例");
return new Car("Byd唐","南京",2500000.0);
}
@Override
public Class getObjectType() {
//指定给Object方法返回的目标类型
return Class.class;
}
@Override
public boolean isSingleton() {
//是否单例
return false;
}
}
...
...
@Test
public void testSpringFactoryBean(){
//从容器中获取工厂bean的实例对象
Car car1 = context.getBean("carFactoryBean", Car.class);
Car car2 = context.getBean("carFactoryBean", Car.class);
//输出对象详情
System.out.println(car 1);
//在容器中添加的实例是 CarFactoryBean 类型,返回的是
//Car(brand=Byd唐, factory=南京, price=2500000.0)
System.out.println("car1 == car2 : " + ( car1 == car2));
//false 说明工厂bean是多例的
}
3、scope 作用域
- singleton 单例 (默认) 容器初始化之前创建;
- prototype 多例 (手动设置) 使用到的时候才创建;
这里 区别于, 整个程序运行期间, 有且只有唯一的实例( 单例模式-懒汉和饿汉);
容器中bean的单例, 不是指当前类的实例在容器中, 只有唯一的实例,而是当 创建bean的实例时,此实例是 单例(容器内唯一),但是 同一个类的实例,容器中 可以创建多个, 每个都是单例的;
@Test
public void testScopeSingleton(){
//从容器中,获取Bus的实例对象
Bus busThree = context.getBean("busTwo", Bus.class);
Bus busFour = context.getBean("busTwo", Bus.class);
System.out.println(busThree);
System.out.println(busFour);
System.out.println("singleton busThree == busFour:"+(busThree == busFour));
//true
}
多例: prototype,不是spring容器中的默认作用, 需要单独指定;
spring容器创建时, 不会自动创建指定作用域为多例的bean的实例,而是每次 通过getBean方法, 获取bean的实例, 才会创建bean的实例;
@Test
public void testScopePrototype(){
Bus busOne = context.getBean("busThree", Bus.class);
Bus busTwo = context.getBean("busThree", Bus.class);
//输入详情
System.out.println(busOne);
System.out.println(busTwo);
System.out.println("prototype busOne == busTwo:"+(busOne == busTwo));
//false
}
Original: https://www.cnblogs.com/xiaoqigui/p/16625420.html
Author: 化羽羽
Title: Spring(一)-初识 + DI+scope
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/621546/
转载文章受原作者版权保护。转载请注明原作者出处!