1、IOC(控制反转)
简单的说就是,创建对象的权利,或者是控制的位置,由JAVA代码转移到spring容器,由spring的容器控制对象的创建,就是控制反转,spring创建对象时,会读取配置文件中的信息,然后使用反射给我们创建好对象之后在容器中存储起来,当我们需要某个对象时,通过id获取对象即可,不需要我们自己去new.
一句话:创建对象交给容器
2、DI(控制反转)
DI Dependency Injection,即“依赖注入” 就是创建属性时给对象属性赋值
对象功能的实现往往要依赖属性的值,那么给对象属性赋值就可以说成是依赖注入
由于对象属性不仅仅是基本数据类型,还可能是其他类,或者引用类型
那么依赖注入将会把更多的对象之间的关系整理到一起,可以行程一个庞大的依赖关系
DI处理的是对象的属性赋值和互相依赖的关系
3、IOC原理
4、XML实现DI
spring中的Bean的管理:
Bean(汉译咖啡豆). 又称JAVABean.其实就是JAVA程序程序中的一个个对象,所以Bean的管理其实就是spring对于JAVA程序中的对象的管理
管理的内容是什么
1 对象的创建 IOC
IOC 叫做控制反转,就是Spring给我们创建对象,然后我们直接用,不用自己NEW,
IOC处理的是对象如何创建的问题
2 属性的赋值 DI
DI处理的是对象的属性赋值和互相依赖的关系
spring给我们提供了两种关于bean的方式
1 基于XML方式的Bean管理
2 基于注解方式的Bean管理
DI给对象属性赋值
1 通过set方法给对象属性赋值
实体类
public class User {
private Integer userid;
private String username;
private String password;
重写toString
空构造器
有参构造器
getter、setter方法
}
XML配置文件
<!--
property 就是在使用set方法实现依赖注入
调用无参构造方法
多个ID不能重复,不同的ID可以对应同一个对象
User user1 = new User()
user1.setuserid()
-->
<bean id="user2" class="com.wml.bean.User" lazy-init="false" scope="prototype">
<property name="userid" value="2"></property>
<property name="username" value="小刚"></property>
<property name="password" value="123456"></property>
</bean>
2 通过有参构造给对象属性赋值
XML配置文件
<!--
调用有参构造方法
User user3 = new User(1,"","")
注意三个参数都要写上只写一个会报错
constructor-arg 就是在使用构造方法实现依赖注入
constructor-arg 的个数必须和某个构造方法的参数个数向对应
name指的是参数名
index指的是参数的索引
value指的是参数值
-->
<bean id="user3" class="com.wml.bean.User" lazy-init="false" scope="prototype">
<constructor-arg name="userid" value="3"></constructor-arg>
<constructor-arg name="username" value="小明"></constructor-arg>
<constructor-arg name="password" value="654321"></constructor-arg>
</bean>
<bean id="user4" class="com.wml.bean.User" lazy-init="false" scope="prototype">
<constructor-arg index="0" value="4"></constructor-arg>
<constructor-arg index="1" value="小黑"></constructor-arg>
<constructor-arg index="2" value="111111"></constructor-arg>
</bean>
3 通过p名称空间和c名称空间给对象属性赋值(实现DI)
添加约束:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
配置对象:
<!--p名称空间,就是对property的简化处理-->
<bean id="user5" class="com.wml.bean.User" p:userid="5" p:username="小花" p:password="222222"></bean>
<!--c名称空间,就是对constructor-arg的简化-->
<bean id="user6" class="com.wml.bean.User" c:userid="6" c:username="小王" c:password="333333"></bean>
4 注入空值和特殊符号
XML配置文件
<bean id="user1" class="com.wml.bean.User">
<!--null值-->
<property name="userid">
<null></null>
</property>
<!--特殊符号 转译字符 < < >> & & -->
<property name="username" value="&xiaoming"></property>
<!-- 特殊符号 <![CDATA[内容]]> -->
<property name="password">
<value><![CDATA[&<123456>]]></value>
</property>
</bean>
5 关于bean引用
实体类
public class Mouse {
private String name;
private Date birthdate;
重写toString
空构造器
有参构造器
getter、setter方法
}
public class Cat {
private String name;
private Mouse mouse1;
重写toString
空构造器
有参构造器
getter、setter方法
}
XML配置文件
(1)引用外部
<!--告诉容器准备一个Date对象-->
<bean id="date1" class="java.util.Date"></bean>
<bean id="mouse1" class="com.wml.bean.Mouse">
<property name="name" value="Jerry"></property>
<!--bean引用 引用外部bean-->
<property name="birthdate" ref="date1"></property>
</bean>
(2)引用内部
<bean id="cat1" class="com.wml.bean.Cat">
<property name="name" value="Tom"></property>
<!--bean引用 引用内部bean-->
<property name="mouse1">
<bean class="com.wml.bean.Mouse">
<property name="name" value="Jerry2"></property>
<property name="birthdate">
<bean class="java.util.Date"></bean>
</property>
</bean>
</property>
</bean>
(3)级联引用内部
<bean id="mouse2" class="com.wml.bean.Mouse"></bean>
<bean id="cat3" class="com.wml.bean.Cat">
<property name="name" value="Tom"></property>
<!--bean引用 级联引用内部bean-->
<property name="mouse1" ref="mouse2"></property>
<!--用反射调用get***方法,获得对象之后,再赋值-->
<property name="mouse1.name" value="Jerry3"></property>
<property name="mouse1.birthdate">
<bean class="java.util.Date"></bean>
</property>
</bean>
6 关于集合注入
实体类
public class Student {
private String[] books;//有很多书集
private Set<String> bookSet;//很多书的名字
private List<String> booksList;
private Map<String,String> bookMap;//书名和作者
private List<Book> bookList1;
重写toString
空构造器
有参构造器
getter、setter方法
}
public class Book {
private String bname;
private String author;
重写toString
空构造器
有参构造器
getter、setter方法
}
XML配置文件
(1)不能公共用
添加约束:
xmlns:p="http://www.springframework.org/schema/p"
<bean id="student1" class="com.wml.bean.Student">
<!--数组属性注入-->
<property name="books">
<array>
<value>JAVA</value>
<value>MYSQL</value>
<value>SPRING</value>
</array>
</property>
<property name="bookSet">
<!--Set集合注入-->
<set>
<value>JAVA</value>
<value>MYSQL</value>
<value>SPRING</value>
</set>
</property>
<property name="booksList">
<!--List集合注入-->
<list>
<value>JAVA</value>
<value>MYSQL</value>
<value>SPRING</value>
</list>
</property>
<property name="bookMap">
<!--Map集合注入-->
<map>
<entry key="JAVA" value="马士兵"></entry>
<entry key="MYSQL" value="马士兵"></entry>
<entry key="SPRING" value="马士兵"></entry>
</map>
</property>
<property name="bookList1">
<!--List对象集合注入-->
<list>
<ref bean="b1"></ref>
<ref bean="b2"></ref>
<ref bean="b3"></ref>
<!--<bean class="com.wml.bean.Book"></bean>
<bean class="com.wml.bean.Book"></bean>
<bean class="com.wml.bean.Book"></bean>-->
</list>
</property>
</bean>
<!--声明多个book对象-->
<bean id="b1" class="com.wml.bean.Book" p:bname="JAVA" p:author="马士兵"></bean>
<bean id="b2" class="com.wml.bean.Book" p:bname="GO" p:author="马士兵"></bean>
<bean id="b3" class="com.wml.bean.Book" p:bname="MYBATIS" p:author="马士兵"></bean>
(2)能公共用
添加约束:
xmlns:util="http://www.springframework.org/schema/util"
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
<!--定义公共集合-->
<util:set id="outerbookSet">
<value>JAVA</value>
<value>MYSQL</value>
<value>SPRING</value>
</util:set>
<util:list id="outerbookList">
<value>JAVA</value>
<value>MYSQL</value>
<value>SPRING</value>
</util:list>
<util:map id="outerbookMap">
<entry key="JAVA" value="马士兵"></entry>
<entry key="MYSQL" value="马士兵"></entry>
<entry key="SPRING" value="马士兵"></entry>
</util:map>
<util:list id="outerbookList1">
<!--声明多个book对象-->
<bean id="b1" class="com.wml.bean.Book" p:bname="JAVA" p:author="马士兵"></bean>
<bean id="b2" class="com.wml.bean.Book" p:bname="GO" p:author="马士兵"></bean>
<bean id="b3" class="com.wml.bean.Book" p:bname="MYBATIS" p:author="马士兵"></bean>
</util:list>
<bean id="student1" class="com.wml.bean.Student">
<!--数组属性注入-->
<property name="books">
<array>
<value>JAVA</value>
<value>MYSQL</value>
<value>SPRING</value>
</array>
</property>
<property name="bookSet" ref="outerbookSet"></property>
<property name="booksList" ref="outerbookList"></property>
<property name="bookMap" ref="outerbookMap"></property>
<property name="bookList1" ref="outerbookList"></property>
</bean>
</beans>
7 工厂方式获取bean
特点 : bean标签中定义的class类不是返回的对象的类,而是生产该对象的工厂
工厂模式:GOF 设计模式
spring中给我们定义好了一个工厂接口,可以生产对象的接口,我们可以通过工厂来获取bean
定义工厂对象 实现 FactoryBean接口
public class BookFactory implements FactoryBean<Book> {
/*public Book getBook(){
Book book = new Book();
book.setBname("JAVA");
book.setAuthor("马士兵");
return book;
}*/
public Book getObject() throws Exception {
Book book = new Book();
book.setBname("JAVA");
book.setAuthor("马士兵");
return book;
}
public Class<?> getObjectType() {
return null;
}
}
XML配置文件
<bean id="book" class="com.wml.bean.BookFactory"></bean>
测试代码
public class Test5 {
@Test
public void testSetBean(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext5.xml");
Book book = applicationContext.getBean("book", Book.class);
System.out.println(book);
}
}
5、生命周期
(1)、
实体类
public class User1 {
private Integer userid;
private String username;
private String password;
@Override
public String toString() {
return "User{" +
"userid=" + userid +
", username=" + username +
", password='" + password + '\'' +
'}';
}
public User1() {
System.out.println("第一步:User1构造");
}
public void setUsername(String username) {
System.out.println("第二步:User1属性赋值");
this.username = username;
}
public void initUser1(){
System.out.println("第三步:User1初始化");
}
public void destoryUser1(){
System.out.println("第五步:销毁User1");
}
public User1(Integer userid, String username, String password) {
this.userid = userid;
this.username = username;
this.password = password;
}
public void setUserid(Integer userid) {
this.userid = userid;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getUserid() {
return userid;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}
XML配置文件
<bean id="book" class="com.wml.bean.BookFactory"></bean>
<bean id="user2" class="com.wml.bean.User1" init-method="initUser1" destroy-method="destoryUser1">
<property name="username" value="小黑"></property>
</bean>
测试代码
public class Test6 {
@Test
public void testLifeCycleBean(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext6.xml");
User1 user2 = applicationContext.getBean("user2", User1.class);
System.out.println("第四步:User对象从容器中获取");
System.out.println(user2);
//关闭容器
applicationContext.close();
}
}
(2)、
BeanPostProcessor接口作用:
如果我们想在Spring容器中完成bean实例化、配置以及其他初始化方法前后要添加一些自己逻辑处理。我们需要定义一个或多个BeanPostProcessor接口实现类,然后注册到Spring IoC容器中。
1、接口中的两个方法都要将传入的bean返回,而不能返回null,如果返回的是null那么我们通过getBean方法将得不到目标。
2、ApplicationContext会自动检测在配置文件中实现了BeanPostProcessor接口的所有bean,并把它们注册为后置处理器,然后在容器创建bean的适当时候调用它,因此部署一个后置处理器同部署其他的bean并没有什么区别。而使用BeanFactory实现的时候,bean 后置处理器必须通过代码显式地去注册,在IoC容器继承体系中的ConfigurableBeanFactory接口中定义了注册方法
创建后置处理器 实现 BeanPostProcesser 重写两个方法
public class MybeanProcesser implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//Object bean 实例化的bean
//String beanName bean的id
System.out.println("bean:初始化方法之前");
return bean;// 这里必须return bean
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("bean:初始化方法之后");
return bean;// 这里必须return bean
}
}
配置后置处理器,对容器中的所有bean添加后置处理器的生命周期
<bean id="user2" class="com.wml.bean.User1" init-method="initUser1" destroy-method="destoryUser1">
<property name="username" value="小黑"></property>
</bean>
<!--配置后置通知处理器-->
<bean id="mybeanprocesser" class="com.wml.beanProcesser.MybeanProcesser"></bean>
测试代码及结果
public class Test7 {
@Test
public void testLifeCycleBean(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext6.xml");
User1 user2 = applicationContext.getBean("user2", User1.class);
System.out.println("第四步:User对象从容器中获取");
System.out.println(user2);
//关闭容器
applicationContext.close();
}
}
6、自动装配(自动注入)
bean自动装配
通过property标签可以手动指定给属性进行注入
我们也可以通过自动转配,完成属性的自动注入,就是自动装配,可以简化DI的配置
实体类
public class Emp {
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"dept=" + dept +
'}';
}
}
public class Dept {
}
XML配置文件
<bean id="dept1" class="com.wml.bean.Dept"></bean>
<!-- <bean id="emp" class="com.wml.bean.Emp">
<property name="dept" ref="dept"></property>
</bean>-->
<bean id="emp" class="com.wml.bean.Emp" autowire="byType"></bean>
<!--
autowire 属性控制自动将容器中的对象注入到当前对象的属性上
byName 根据目标id值和属性值注入,要保证当前对象的属性值和目标对象的id值一致
byType 根据类型注入,要保证相同类型的目标对象在容器中只有一个实例
-->
测试代码
public class Test8 {
@Test
public void testLifeCycleBean(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext7.xml");
Emp emp = applicationContext.getBean("emp", Emp.class);
System.out.println(emp);
}
}
7、Spring_使用外部属性配置文件
spring容器可以读取.properties属性配置文件,可以将文件中的信息注入给bean
例如:引入Druid数据源,配置连接池信息
pom.xml中导入spring依赖jar
导入Druid依赖和mysql-connector依赖
<packaging>jar</packaging>
<!--pom.xml中导入spring依赖jar-->
<dependencies>
<!--context上下文,容器 只需导入他就可以beans、core、spel不需要导入-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!--junit单元测试测试包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
</dependencies>
XML配置文件
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
<!--读取jdbc.properties属性配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--给链接池进行配置时要进行给链接数据库的四要素进行配置-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc_username}"></property>
<property name="password" value="${jdbc_password}"></property>
<property name="url" value="${jdbc_url}"></property>
<property name="driverClassName" value="${jdbc_driver}"></property>
<!--初始化连接容量-->
<!--<property name="initialSize" value="1"></property>-->
</bean>
准备属性配置文件:
resources目录下准备一个jdbc.properties属性配置文件
jdbc_username=root
jdbc_password=root
jdbc_url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=ture&characterEncoding=UTF-8serverTimezone=UTC&allowPublicKeyRetireval=ture
jdbc_driver=com.mysql.cj.jdbc.Driver
测试代码
public class Test9 {
@Test
public void testdataSourceBean() throws SQLException {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext8.xml");
DataSource dataSource = applicationContext.getBean("dataSource", DataSource.class);
System.out.println(dataSource);
/* Connection connection = dataSource.getConnection();*/
}
}