1、获取bean实例的三种方式
1.1 id 属性
1.1.1 jar
 - <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <spring.version>4.3.18.RELEASE</spring.version>
- <lombok.version>1.16.18</lombok.version>
- <junit.version>4.11</junit.version>
- </properties>
- <dependencies>
-
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-beans</artifactId>
- <version>${spring.version}</version>
- </dependency>
-
-
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-core</artifactId>
- <version>${spring.version}</version>
- </dependency>
-
-
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- <version>${spring.version}</version>
- </dependency>
-
-
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-expression</artifactId>
- <version>${spring.version}</version>
- </dependency>
-
- </dependencies>
复制代码 1.1.2 application.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <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="userOne" >
- <property name="nickName" value="kh96_spring_one"></property>
- </bean>
- </beans>
复制代码 标签:定义一个实例对象,会自动被创建 并 交给spring容器进行管理:
- id 属性:被spring容器进行管理的实例的 唯一标识,整个容器中,只能是唯一的(不可重复);
- class属性:指定创建当前实例对象的类型(全类名),spring底层是使用的 反射机制 ,根据指定的目标类型,创建目标实例(必须有 空参构造)
- 子标签:给当前创建对象的属性值
- name:指定对象的属性名
- value: 给属性赋值
1.1.3 测试
- @Test
- public void testSpringPrimer(){
- //1.创建spring的核心容器对象(引用上下文对象),解析spring的核心配置文件,将文件中的bean标签进行实例化(创建对象并赋值)
- ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- //2. 写法一: 从容器中获取实例对象,根据核心配置文件中,配置的bean标签的id属性值
- //<bean id="carTwo" >
- <constructor-arg value="AudiA4"></constructor-arg>
- <constructor-arg value="一汽"></constructor-arg>
- <constructor-arg value="320000"></constructor-arg>
- </bean>不足:强制转化,容易出现转换错误
- User userOne = (User) context.getBean("userOne");
-
- userOne.sayHello();
- //对比以前创建对象的写法(对象必须手动new创建,并手动赋值)
- User userOld = new User();
- userOld.setNickName("kh96_old");
- userOld.sayHello();
-
- }
复制代码 1.1.4 总结
通过id属性,获取实例对象后需要强制转换,容易出现强制转化错误;
1.2 class 属性
1.2.1 测试
- //写法二:从容器中获取实例对象,根据核心配置文件中,配置的bean标签的class属性指定的目标类型
- User userTwo = context.getBean(User.class);
- userTwo.sayHello();
复制代码 1.2.2 总结
不足:如果存在同类型的多个实例,会报异常;
1.2.2.1 application.xml
当用多个同类型的实例:- ...
- <bean id="userOne" >
- <property name="nickName" value="kh96_spring_one"></property>
- </bean>
- <bean id="userTwo" >
- <property name="nickName" value="kh96_spring_two"></property>
- </bean>
- ...
复制代码 1.2.2.2 测试
- 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属性去获取实例,但是有多个相同类型的实例,所以无法确定你要获取的是哪一个;
1.3 id 属性 和 class 属性 (推荐)
1.3.1 测试
- //写法三:从容器中获取实例对象,根据配置文件中,配置的bean标签的id属性值和class属性指定的目标类型
- User userTwoThree = context.getBean("userTwo", User.class);
复制代码 1.3.2 总结
能够确定唯一实例,推荐使用;
1.4 id 不能重复注意点
配置文件中的id必须是唯一的;
如果id不唯一:两个id一样的实例- ...
- <bean id="userOne" >
- <property name="nickName" value="kh96_spring_one"></property>
- </bean>
- <bean id="userTwo" >
- <property name="nickName" value="kh96_spring_two"></property>
- </bean>
- ...
复制代码 报错:
BeanDefinitionParsingException: Configuration problem: Bean name 'userOne' is already used in this element
提示 id 为 userOne 的实例已经存在;
1.5 实例化时机
当初始化spring的容器对象时,会将核心配置文件中所有的bean实例化,不是使用哪个,创建哪个;
2、DI
IOC(控制反转是一种思想),DI是IOC的一种实现方式;
2.1 set 方式注入
2.1.1 实体
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class User {
- //用户昵称
- //普通参数
- private String nickName;
- //私家车
- //实体参数
- private Car car;
- //喜欢的书
- //数组参数
- private String[] books;
- //爱好
- //list集合参数
- private List<String> hobbies;
- //喜欢的游戏
- //set 集合
- private Set<String> games;
- //卡包
- //map参数
- private Map<String,String> cards;
- //在校信息
- //properties参数
- private Properties info;
- //是否有女朋友 (主要是演示赋值为null,其他类型都可以)
- //空参数注入
- private Boolean wife;
- }
复制代码 2.1.2 参数 注入
2.1.3 测试
- @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
- )
复制代码 2.2 Constructor 构造器注入
2.2.1 按照默认顺序 注入
2.2.1.1 参数注入
- <bean id="carTwo" >
- <constructor-arg value="AudiA4"></constructor-arg>
- <constructor-arg value="一汽"></constructor-arg>
- <constructor-arg value="320000"></constructor-arg>
- </bean>
复制代码 2.2.1.2 测试
- @Test
- public void testSpringDIConstructor(){
- Car carTwo = context.getBean("carTwo", Car.class);
- //输出对象详情
- System.out.println(carTwo);
- }
复制代码 2.2.2 根据 参数的下标 和 类型 注入
2.2.2.1 参数注入
- <bean id="carTwo" >
- <constructor-arg value="AudiA4"></constructor-arg>
- <constructor-arg value="一汽"></constructor-arg>
- <constructor-arg value="320000"></constructor-arg>
- </bean>
复制代码 2.2.2.2 测试
- @Test
- public void testSpringDIConstructor2(){
- Car carTwo = context.getBean("carThree", Car.class);
- //输入对象详情
- System.out.println(carTwo);
- }
复制代码 2.3 自定义 实体工厂bean
自定义实体工厂bean ,必须实现FactoryBean接口;
普通bean 与 工厂bean 的区别:
- 普通 bean:在配置文件中定义 bean 类型 就是 返回类型
- 工厂 bean:在配置文件定义 bean 类型 和 返回类型 不一样
2.3.1 返回bean
- @Data
- @ToString
- public class Car {
- /*
- 品牌
- */
- private String brand;
- /*
- 厂商
- */
- private String factory;
- /*
- 价格
- */
- private Double price;
- }
复制代码 2.3.2 实体工厂 bean
- 在spring容器初始化时,创建当前工厂bean的实例对象,但是真实返回的不是当前类的实例对象,而是当前类的实例对象返回的目标实例对象(自定义);
- 作用:可以在程序中,实现自定义创建实例(还可以增加业务逻辑处理),放入容器;
- 存在的原因:spring框架对外开放了一个入口,可以让其他的开发人员参与到spring底层创建bean的实例过程中去,给整合其他框架使用的,比如mybatis;
- public class CarFactoryBean implements FactoryBean<Car> {
- @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;
- }
- }
复制代码 2.3.3 工厂bean容器中添加自定义实例对象
- ...
- <bean id="carFactoryBean" ></bean>
- ...
复制代码 2.3.4 测试
- @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 多例 (手动设置) 使用到的时候才创建;
3.1 singleton 单例
这里区别于,整个程序运行期间,有且只有唯一的实例(单例模式-懒汉和饿汉);
而容器中bean的单例,不是指当前类的实例在容器中,只有唯一的实例,而是当创建bean的实例时,此实例是单例(容器内唯一),但是同一个类的实例,容器中可以创建多个,每个都是单例的;
3.1.1 配置bean
- <bean id="carTwo" >
- <constructor-arg value="AudiA4"></constructor-arg>
- <constructor-arg value="一汽"></constructor-arg>
- <constructor-arg value="320000"></constructor-arg>
- </bean>
复制代码 3.1.2 测试
- @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
- }
复制代码 3.2 prototype 多例
多例:prototype,不是spring容器中的默认作用,需要单独指定;
spring容器创建时,不会自动创建指定作用域为多例的bean的实例,而是每次通过getBean方法,获取bean的实例,才会创建bean的实例;
3.2.1 配置bean
- <bean id="carTwo" >
- <constructor-arg value="AudiA4"></constructor-arg>
- <constructor-arg value="一汽"></constructor-arg>
- <constructor-arg value="320000"></constructor-arg>
- </bean>
复制代码 3.2.2 测试
- @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
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |