IOC容器
IOC思想基于IOC容器,IOC容器底层就是对象工厂
IOC底层
通过控制反转,使用xml配置文件和反射机制实现对对象的创建
IOC接口
实现IOC容器的两种方式
(1)BeanFactory
Spring内部使用
加载配置文件时不会创建对象,只有在使用时创建对象
(2)ApplicationContext
BeanFactory的子接口,面向开发人员
加载配置文件时会创建对象
IOC容器实现类
① FileSystemXMLApplicationContext:参数为文件路径
② ClassPathXMLApplicationContext:参数为类路径
基于xml实现bean管理
1.创建对象
User.java
public class User {
public void add(){
System.out.println("add.......");
}
}
bean.xml
<!-- 1.配置User对象创建-->
<bean id="user" class="com.lin.pojo.User"></bean>
(1)属性
-
id:唯一标识,对象别名,通过这个名字得到对象
-
class:将要创建对象的类全路径
(2)创建对象时默认执行无参构造
2.依赖注入
(1)setter方法注入:property
Book.java
@Data
public class Book {
private String bname;
}
bean1.xml
<!-- setter-->
<!-- 1.创建对象-->
<bean id="b" class="com.lin.pojo.Book">
<!-- name:property name value:将要注入的值-->
<property name="bname" value="123"></property>
</bean>
Test.java
@Test
public void test02(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
Book book1 = context.getBean("b", Book.class);
System.out.println(book1.getBname());
}
(2)有参构造方法注入:constructor-arg
Orders.java
@AllArgsConstructor
public class Orders {
private String oname;
private String address;
@Override
public String toString() {
return this.address + " : " + this.oname;
}
}
bean1.xml
<!-- 有参构造-->
<bean id="orders" class="com.lin.pojo.Orders">
<constructor-arg name="oname" value="123"></constructor-arg>
<constructor-arg name="address" value="456"></constructor-arg>
</bean>
<!-- 或者-->
<bean id="orders" class="com.lin.pojo.Orders">
<!-- 通过有参构造方法参数的索引值匹配 -->
<constructor-arg index="0" value="123"></constructor-arg>
<constructor-arg index="1" value="456"></constructor-arg>
</bean>
Test.java
@Test
public void test03(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
Orders or = context.getBean("orders", Orders.class);
System.out.println(or.toString());
}
3.注入属性
(1)字面量
- 空值null
<property name="address">
<null></null>
</property>
- 属性包含特殊符号,使用< value >标签
<!-- 1.转义字符 -->
<!-- 2.CD -->
<property name="bname">
<value>
<![CDATA[<<Android>>]]>>
</value>
</property>
(2)外部bean
- 创建两个类service和dao
- 在service调用dao里面的方法
- 在spring配置文件进行配置
UserService.java
public class UserService {
//创建UserDao属性并生成set方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println("add---------service");
//service类调用dao
//1.原始方式:new UserDaoImpl ,调用方法
//2.spring:创建两个类,将UserDao注入到UserService
userDao.update();
}
}
UserDao.java
public interface UserDao {
void update();
}
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("dao update---------");
}
}
bean2.xml
<!-- 1. service and dao create-->
<bean id="service" class="com.lin.service.UserService">
<!-- 2.注入UserDao对象 name:属性名 ref:将要注入对象的id-->
<property name="userDao" ref="dao"></property>
</bean>
<bean id="dao" class="com.lin.dao.UserDaoImpl"></bean>
</beans>
Test02.java
@Test
public void serviceAndDao(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
UserService service = context.getBean("service", UserService.class);
service.add();
}
(3)内部bean
-
一对多
-
在实体类中表示一对多的关系—在多的那方加入一
-
spring配置文件配置
Emp.java
//员工类
public class Emp {
private String ename;
private String gender;
private Dept dept; //员工属于某一个部门
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Emp{" +
"ename='" + ename + '\'' +
", gender='" + gender + '\'' +
", dept=" + dept +
'}';
}
}
Dept.java
//部门类
public class Dept {
private String dname;
public void setDname(String dname){
this.dname=dname;
}
}
bean3.xml
<!-- 内部bean-->
<bean id="emp" class="com.lin.bean.Emp">
<!-- 设置普通属性-->
<property name="ename" value="tom"></property>
<property name="gender" value="nv"></property>
<!-- 对象类型属性-->
<property name="dept">
<bean id="dept" class="com.lin.bean.Dept">
<property name="dname" value="aqy"></property>
</bean>
</property>
</bean>
Test03.java
@Test
public void Test01(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
Emp emp = context.getBean("emp", Emp.class);
System.out.println(emp.toString());
}
(4)级联赋值(与外部bean相似)
bean4.xml
<!-- 级联赋值 第一种写法-->
<bean id="emp" class="com.lin.bean.Emp">
<!-- 设置普通属性-->
<property name="ename" value="tom"></property>
<property name="gender" value="nv"></property>
<!-- 级联赋值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.lin.bean.Dept">
<property name="dname" value="cwb"></property>
</bean>
------------------------------------------------------------------------------
<!-- 级联赋值 第二种写法-->
<bean id="emp" class="com.lin.bean.Emp">
<!-- 设置普通属性-->
<property name="ename" value="tom"></property>
<property name="gender" value="nv"></property>
<!-- 级联赋值-->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="vjb"></property>
</bean>
Test03.java
@Test
public void Test02(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
Emp emp = context.getBean("emp", Emp.class);
System.out.println(emp.toString());
}
(5)注入集合
- 注入数组
- 注入List
- 注入Map
- 注入Set
Stu.java
public class Stu {
//1.数组类型的属性
private String[] courses;
//2.List集合类型属性
private List<String> list;
//3.Map集合类型属性
private Map<String,String> maps;
//4.set集合类型的属性
private Set<String> sets;
//setter省略
bean1.xml
<!-- 集合类型属性的注入-->
<bean id="stu" class="com.lin.collectiontype.Stu">
<!-- 数组-->
<property name="courses" >
<array>
<value>java</value>
<value>c++</value>
</array>
</property>
<!-- list-->
<property name="list">
<list>
<value>zhangs</value>
<value>xiaosan</value>
</list>
</property>
<!-- Map-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry value="PHP" key="php"></entry>
</map>
</property>
<!-- set-->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
</bean>
Test01.java
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Stu stu = context.getBean("stu", Stu.class);
System.out.println(stu);
}
4.在集合中设置对象类型的值
Course.java
public class Course {
private String cname;
// setter and toString omit
}
Stu.java
public class Stu {
//学生所学多门课
private List<Course> courseList;
// setter and toString omit
}
bean1.xml
<!-- 集合类型属性的注入-->
<bean id="stu" class="com.lin.collectiontype.Stu">
<!-- List集合与对象-->
<property name="courseList">
<list>
<!-- bean:对象bean的id-->
<ref bean="c1"></ref>
<ref bean="c2"></ref>
</list>
</property>
</bean>
<bean id="c1" class="com.lin.collectiontype.Course">
<property name="cname" value="S"></property>
</bean>
<bean id="c2" class="com.lin.collectiontype.Course">
<property name="cname" value="M"></property>
</bean>
Test01.java
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Stu stu = context.getBean("stu", Stu.class);
System.out.println(stu);
}
5.集合注入的部分提取为公共
-
在spring配置文件中引入util名称空间
-
使用util标签完成list集合注入的提取
Book.java
public class Book {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
@Override
public String toString() {
return "Book{" +
"list=" + list +
'}';
}
}
bean2.xml
<!-- 1.提取list集合属性-->
<util:list id="bookL">
<value>yjj</value>
<value>jysg</value>
<value>xlsbz</value>
</util:list>
<!-- 2.注入-->
<bean id="book" class="com.lin.collectiontype.Book">
<property name="list" ref="bookL"></property>
</bean>
<bean id="book2" class="com.lin.collectiontype.Book">
<property name="list" ref="bookL"></property>
</bean>
Test01.java
@Test
public void test02(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean2.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
book=context.getBean("book2",Book.class);
System.out.println(book);
}
4、FactoryBean
Spring有两种类型的bean
- 普通bean:在配置文件中,定义的bean的类型与返回类型一致
- 工厂bean:在配置文件中,定义的bean的类型与返回的类型不一致
- 创建类,让这个类作为工厂bean(实现FactoryBean接口)
- 实现接口中的方法,在方法中定义返回类型
Mybean.java
public class Mybean implements FactoryBean<Course> {
//定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("abc");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
bean3.xml
<bean id="mybean" class="com.lin.collectiontype.com.lin.factoryBean.Mybean">
</bean>
Test01.java
@Test
public void test03(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
Course course = context.getBean("mybean", Course.class);
System.out.println(course);
}
5.bean的作用域
-
在Spring里面,默认情况下,bean为单实例
-
设置单实例或者多实例
-
bean标签中的(scope)属性
-
默认值,singleton:单实例,在加载spring配置文件的时候创建对象
-
prototype:多实例,在调用getBean方法的时候创建对象
-
6.bean的生命周期
1、
(1)创建bean实例(无参构造)
(2)属性值(setter)
(3)调用bean的初始化方法(init bean标签配置)
(4)获取bean实例(getBean)
(5)销毁bean(destroy bean标签配置)
2、bean的后置处理器
(1)创建bean实例(无参构造)
(2)属性值(setter)
(3) bean的实例传递给bean的后置处理器的方法
(4)调用bean的初始化方法(init bean标签配置)
(5) bean的实例传递给bean的后置处理器的方法
(6)获取bean实例(getBean)
(7)销毁bean(destroy bean标签配置)
xml自动装配
根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
Dept.java、Emp.java
public class Dept {
@Override
public String toString() {
return super.toString();
}
}
public class Emp {
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"dept=" + dept +
'}';
}
}
bean5.xml
<!-- 自动装配 属性-->
<!-- bean标签 autowire:
byName根据属性名称注入,bean id的值与属性名称一致
byType根据属性类型注入-->
<bean id="emp" class="com.lin.autowire.Emp" autowire="byName"></bean>
<bean id="dept" class="com.lin.autowire.Dept"></bean>
<bean id="emp2" class="com.lin.autowire.Emp" autowire="byType"></bean>
test04.java
@Test
public void test04(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");
Emp emp = context.getBean("emp", Emp.class);
System.out.println(emp);
Emp emp2 = context.getBean("emp2", Emp.class);
System.out.println(emp2);
}
引入外部属性文件
1.直接配置数据库信息
(1)连接池
bean6.xml
<!-- 配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/lin?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
2.引入外部属性文件
(1)创建properties格式的属性文件,写数据库信息
jdbc.properties
prop.driverClass=com.alibaba.druid.pool.DruidDataSource
prop.url=jdbc:mysql://localhost:3306/lin?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
prop.username=root
prop.password=123456
(2)把外部properties引入spring配置
-
1.context名称空间
-
2.引入外部文件
bean6.xml
<!-- 引入外部文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>