1.背景
1.操作bean的意思是IOC如何创建对象(放入),如何注入属性(取出使用)。
2.操作bean有两种方式
方式一:xml的形式(用得少)
方式二:注解的形式(经常使用)
而且区别:本质上是一样的,只是写的形式不一样
理解的核心:只有先把对象放入IOC容器,才可以从容器中取出来!
2.xml操作bean
2.1.普通对象操作
1.常规使用
准备工作:创建一个订单对象
package com.ldp.model;/*** @Copyright (C) XXXXXXXXXXX科技股份技有限公司* @Author: lidongping* @Date: 2021-01-11 14:28* @Description:*/public class Order {private String orderNo;private String orderName;/*** 无参数构造方法*/public Order() {}/*** 有参数构造方法** @param orderNo* @param orderName*/public Order(String orderNo, String orderName) {this.orderNo = orderNo;this.orderName = orderName;}// get set 略}
需求:使用IOC操作bean完成如下对象的创建
public class Testbean02 {/*** 使用传统的方式创建对象* 那么如果采用IOC的方式如何创建呢?*/@Testpublic void test01() {// 1.简单的创建对象Order order1 = new Order();System.out.println(order1);// 2.创建对象并给对象设定值Order order2 = new Order();order2.setOrderName("NO002");order2.setOrderName("购买苹果");System.out.println(order2);// 3.构造器创建方法并设定值Order order3 = new Order("NO003", "购买香蕉");System.out.println(order3);// 4.创建对象并设置特殊值Order order4 = new Order();order4.setOrderNo(null);order4.setOrderName("购买课程<java项目面试专题>");}}
答案:IOC实现如上的对象创建如下
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:P="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--1.简单的创建对象Order order1 = new Order();System.out.println(order1);--><bean id="order1" class="com.ldp.model.Order"></bean><!--// 2.创建对象并给对象设定值Order order2 = new Order();order2.setOrderName("NO002");order2.setOrderName("购买苹果");System.out.println(order2);注意:必须有无参数构造器--><bean id="order2" class="com.ldp.model.Order"><property name="orderNo" value="NO001"></property><property name="orderName" value="购买苹果"></property></bean><!--// 3.构造器创建方法并设定值Order order3 = new Order("NO003", "购买香蕉");System.out.println(order3);注意:必须有待着两个参数的构造器--><bean id="order3" class="com.ldp.model.Order"><constructor-arg name="orderNo" value="NO003"></constructor-arg><constructor-arg name="orderName" value="购买香蕉"></constructor-arg></bean><!--// 4.创建对象并设置特殊值Order order4 =new Order();order4.setOrderNo(null);order4.setOrderName("购买课程<java项目面试专题>");处理特殊字符: < > 的两种方式方式一:转义的方式 < >方式二:<![CDATA[ 这里写值 ]]> ,例如:<![CDATA[ 购买课程<java项目面试专题> ]]>扩展:处理特殊字符在xml中是通用的实际案例一:我们在学习mybatis时,在xml中写sql语句经常用到 大于 小于符号 也都是这样转义的实际案例二:在做微信支付的时候,因为微信的采用的是xml数据格式,为了代码的健壮性,我们会把所有的值都是用 <![CDATA[ ]]>,微信的官方文档也是这样提供的--><bean id="order4" class="com.ldp.model.Order"><property name="orderName"><null/> <!--表示将orderNO设置为null--></property><property name="orderNo"><value> <![CDATA[购买课程<java项目面试专题>]]> </value> <!--处理特殊字符: < > --></property></bean><!--p 名称空间注入,相当于是简写而已1.先在头部引入 xmlns:P="http://www.springframework.org/schema/p2.使用: P:orderNo="N002" P:orderName="购买苹果"--><bean id="order2" class="com.ldp.model.Order" P:orderNo="N002" P:orderName="购买苹果"></bean></beans>
2.注入外部bean,也就是在service 中注入dao的应用场景
准备工作:
1.创建一个ProductDao
public class ProductDao {/*** 模拟查询产品dao** @return*/public List<Product> query() {List<Product> list = new ArrayList<>();return list;}}
2.创建一个ProductServiceImpl
public class ProductServiceImpl {private ProductDao productDao;public ProductDao getProductDao() {return productDao;}public void setProductDao(ProductDao productDao) {this.productDao = productDao;}}
IOC实现注入外部bean,使用ref=“productDao”
<!-- 配置productDao--><bean id="productDao" class="com.ldp.dao.ProductDao"></bean><!--配置productServiceImpl--><bean id="productServiceImpl" class="com.ldp.service.ProductServiceImpl"><property name="productDao" ref="productDao"></property></bean>
3.内部注入,其实写法差不多
<!--内部注入--><bean id="productServiceImpl" class="com.ldp.service.ProductServiceImpl"><property name="productDao"><bean id="productDao" class="com.ldp.dao.ProductDao"></bean></property></bean>
2.2.集合属性操作
准备工作:创建一个User对象
package com.ldp.model;import java.util.List;import java.util.Map;/*** @Copyright (C) XXXXXXXXXXX科技股份技有限公司* @Author: lidongping* @Date: 2021-01-11 16:36* @Description: <p>* xml 注入集合属性* 1、注入数组类型属性* 2、注入 List 集合类型属性* 3、注入 Map 集合类型属性* 创建类,定义数组、list、map、set 类型属性,生成对应 get,set 方法* </p>*/public class User {/*** 用户名*/private String userName;/*** 特长*/private String[] hobbyArray;/*** 学习科目*/private List<String> courseList;/*** 各科目得分*/private Map<String, String> scoreMap;// get set 略}
1.注入数组
2.注入List集合
3.注入Map集合
IOC注入实现
<?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="user" class="com.ldp.model.User"><property name="userName" value="张无忌"></property><property name="hobbyArray"><array><value>九阳神功</value><value>乾坤大挪移</value></array></property><property name="courseList"><list><value>java</value><value>c#</value></list></property><property name="scoreMap"><map><entry key="java" value="90"></entry><entry key="c#" value="70"></entry></map></property></bean></beans>
2.3.FactoryBean结合xml的方式操作bean
1、Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
2、普通 bean:在配置文件中定义 bean 类型就是返回类型
3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
步骤一: 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
package com.ldp.factoryBean;import com.ldp.model.Product;import org.springframework.beans.factory.FactoryBean;/*** @Copyright (C) XXXXXXXXXXX科技股份技有限公司* @Author: lidongping* @Date: 2021-01-11 17:17* @Description:*/public class ProductFactoryBean implements FactoryBean<Product> {@Overridepublic Product getObject() throws Exception {return new Product();}@Overridepublic Class<?> getObjectType() {return null;}}
步骤二: IOC中装配
步骤三:测试
/*** 普通bean与工厂bean的区别* 1、Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)* 2、普通 bean:在配置文件中定义 bean 类型就是返回类型* 3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样*/@Testpublic void test02() {// 1.加载 spring 配置文件 (这个时候 bean1.xml 中的所有对象已经创建)ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");// 2.获取配置创建的对象Product product = context.getBean("productFactoryBean", Product.class);// 3.使用对象System.out.println(product);}
2.4.bean单例多例设置
1.默认的bean是单例的测试如下:
2.如何让bean为多例
/*** 默认创建的bean是单例还是多例的?* 答案:单例的* <p>* 如何为多例呢?* 加一个:scope="prototype"* <bean id="product2" class="com.ldp.model.Product" scope="prototype"></bean>* <p>* 重要说明:* 1.设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象* 2.设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建 对象,在调用getBean 方法时候创建多实例对象* 3.注意实际生产中一般使用单例*/@Testpublic void test03() {// 1.加载 spring 配置文件 (这个时候 bean1.xml 中的所有对象已经创建)ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");// 2.获取配置创建的对象Product product1 = context.getBean("product", Product.class);System.out.println(product1);Product product2 = context.getBean("product", Product.class);System.out.println(product2);}
2.5.bean生命周期
生命周期顾名思义:就是从创建到回收的整过过程(从生—》死)
/*** bean 生命周期* 1)调用构造器,通过构造器创建 bean 实例* 2)给bean设置属性值(调用set方法方法)* 3)调用 bean 的初始化的方法(需要进行配置初始化的方法)* 4)使用bean....* 5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)* xml配置如下:* <bean id="product2" class="com.ldp.model.Product" init-method="initProduct" destroy-method="destroyProduct">* <property name="name" value="西瓜"></property>* </bean>*/@Testpublic void test04() {// 1.加载 spring 配置文件 (这个时候 bean1.xml 中的所有对象已经创建)ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");// 2.获取配置创建的对象Product product = context.getBean("product2", Product.class);System.out.println(product);// 关闭容器context.close();}
BeanPostProcessor 后置处理器的理解
步骤一:添加一个后置处理器
package com.ldp.postProcessor;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;/*** @Copyright (C) XXXXXXXXXXX科技股份技有限公司* @Author: lidongping* @Date: 2021-01-11 18:34* @Description: <p>* bean的后置处理器* </p>*/public class DemoPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("初始化执行前的方法.........beanName=" + beanName);return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("初始化执行 后 的方法.........beanName=" + beanName);return bean;}}
步骤二:xml配置IOC
步骤三:测试
/*** bean 生命周期* 1)调用构造器,通过构造器创建 bean 实例* 2)给bean设置属性值(调用set方法方法)* ------把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization* 3)调用 bean 的初始化的方法(需要进行配置初始化的方法)* ------把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization* 4)使用bean....* 5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)*/@Testpublic void test04() {// 1.加载 spring 配置文件 (这个时候 bean1.xml 中的所有对象已经创建)ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml");// 2.获取配置创建的对象Product product = context.getBean("product", Product.class);System.out.println(product);// 关闭容器context.close();}
步骤四:测试结果
调用构造方法.....调用set方法.....初始化执行前的方法.........beanName=product调用初始化方法......初始化执行 后 的方法.........beanName=productcom.ldp.model.Product@64f6106c调用销毁化方法......
2.6.xml自动装配
概念:自动装配的意思就是,bean会根据类型或者id(名称),自动去找容器中满足条件的对象
注意:bean中id是不会重复的,但是配置的时候类可能会重复,因此
1.如果同一个类型配置了多次,那么如果根据类型装配会是什么情况呢?
报错:expected single matching bean but found 2: productDao,productDao2
2.如果没有这个类会是什么情况呢? 装配值为null,也就是不会装配,但是也不会报错
3.如果根据名称装配,没有这个名称会怎么样呢? 装配值为null,也就是不会装配,但是也不会报错
根据id名称装配
<!--自动装配演示 根据id名称装配需求:以在ProductServiceImpl 中装配一个 ProductDao 为例讲解--><bean id="productDao" class="com.ldp.dao.ProductDao"></bean><!--bean 标签属性 autowire,配置自动装配autowire 属性常用两个值:byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样 ,《例如这里的 productDao 一定要与 bean id 值一致,因此我们经常采用规范命名 装配对象的类名首字母小写作为装配的id》byType 根据属性类型注入--><bean id="productServiceImpl" class="com.ldp.service.ProductServiceImpl" autowire="byName"><!--自动装配不写这个dao注入,对象中也会有这个值<property name="productDao" ref="productDao"></property>--></bean>
根据类型装配
<!--自动装配演示 根据类型装配需求:以在ProductServiceImpl 中装配一个 ProductDao 为例讲解--><bean id="productDao" class="com.ldp.dao.ProductDao"></bean><!--bean 标签属性 autowire,配置自动装配autowire 属性常用两个值:byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样 ,《例如这里的 productDao 一定要与 bean id 值一致,因此我们经常采用规范命名 装配对象的类名首字母小写作为装配的id》byType 根据属性类型注入--><bean id="productServiceImpl" class="com.ldp.service.ProductServiceImpl" autowire="byType"><!--自动装配不写这个dao注入,对象中也会有这个值<property name="productDao" ref="productDao"></property>--></bean>
2.7.装配值来自外部配置文件
这里以我们常用的数据库配置为例进行讲解
外部配置文件:db.properties
mysql.driverClassName=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/ldp-data
mysql.username=root
mysql.password=admin
spring的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"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/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- IOC 操作 Bean 管理-外部属性文件--><!--1.直接写参数配置连接池缺点:参数与代码耦合在一起,不便于维护--><bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/ldp-data"></property><property name="username" value="root"></property><property name="password" value="admin"></property></bean><!--引入外部属性文件--><context:property-placeholder location="classpath:db.properties"/><!--配置连接池--><bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${mysql.driverClassName}"></property><property name="url" value="${mysql.url}"></property><property name="username" value="${mysql.username}"></property><property name="password" value="${mysql.password}"></property></bean></beans>
3.注解的方式操作bean
这个用法用得很多,也很简单相信大家都已经很熟练了!
1、什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化 xml 配置
2、Spring 针对 Bean 管理中创建对象提供注解
(1)@Repository:一般贴在dao上
(2)@Service :一般贴在业务类上
(3)@Controller :控制层类上
(4)@Component:一般贴在非dao、service、controller的类上
上面四个注解功能是一样的,都可以用来创建 bean 实例
3.1.使用注解将对象放入spring容器
具体用法:
步骤一:编写spring配置文件
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"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/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- IOC 操作 Bean 管理-基于注解方式--><!--开启组件扫描如果扫描多个包,多个包使用逗号隔开--><context:component-scan base-package="com.ldp"></context:component-scan></beans>
步骤二:贴注解
// 表示使用注解将对象加入spring容器@Servicepublic class TestDemoServiceImpl {public void method() {System.out.println("使用注解的方式加入spring容器...");}}
3.2.使用注解的方式将属性注入到对象中
1.简单使用
// 表示使用注解将对象加入spring容器@Servicepublic class TestDemoServiceImpl {// 使用注解将对象放入spring容器@Autowiredprivate ProductDao productDao;public void method() {System.out.println("使用注解的方式加入spring容器...");}}
2.注解@Qualifier:根据名称进行注入
// 表示使用注解将对象加入spring容器@Servicepublic class TestDemoServiceImpl {// 使用注解将对象放入spring容器@Autowired//根据名称进行注入@Qualifier(value = "productDao")private ProductDao productDao;public void method() {System.out.println("使用注解的方式加入spring容器...");}}
3.注解@Resource:可以根据类型注入,可以根据名称注入
// 表示使用注解将对象加入spring容器@Servicepublic class TestDemoServiceImpl {// 使用注解将对象放入spring容器// @Autowired//根据名称进行注入// @Qualifier(value = "productDao")//根据名称进行注入(一般不使用@Resource注解)@Resource(name = "productDao")private ProductDao productDao;public void method() {System.out.println("使用注解的方式加入spring容器...");}}
4.注解@Value:注入普通类型属性或外部配置文件属性
// 注解注入普通属性@Value("张三")private String name;// 注解注入外部配置文件普通属性@Value("${mysql.url}")private String url;
4.全注解开发
步骤一:配置类
//作为配置类,替代 xml 配置文件@Configuration@ComponentScan(basePackages = {"com.ldp"})// 读取外部配置文件@PropertySource("classpath:db.properties")public class SpringConfig {}
步骤二:测试
@Testpublic void test01() {//加载配置类ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);// 获取容器对象TestDemoServiceImpl testDemoService = context.getBean("testDemoServiceImpl", TestDemoServiceImpl.class);// 执行方法testDemoService.method();}
5.总结
到此IOC容器相关的知识点已经梳理完成,如果还有不懂的可以结合视频讲解学习,该博客已录制成视频课程,也可以单独问我!
