文章目录
1、IOC本质
**控制反转loC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现loC的一种方法,**也有人认为DI只是loC的另一种说法。没有IoC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的.
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
1.1、拓展:关于Spring Boot 和 Spring Cloud
-
Spring Boot
- 一个快速开发的脚手架。
- 基于SpringBoot可以快速开发单个微服务。
- 约定大于配置
-
Spring Cloud
- Spring Cloud是基于SpringBoot实现的
大多数公司都使用SpringBoot快速开发,学习SpringBoot的前提,是需要完全掌握Spring及SpringMVC!承上启下的作用!
2、HelloSpring
ApplicationContext就是一个百宝箱
ApplicationContext是Spring的核心,Context我们通常解释为上下文环境,我想用“容器”来表述它更容易理解一些,ApplicationContext则是“应用的容器”了:Spring把Bean放在这个容器中,在需要的时候,用getBean方法取出。
beans.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">
<!--使Hspring来创建对象,在:spring这些都成为Bean
类型变量名= new类型();
Hello hello = new Hello();
id =变量名
class = new的时象:
property相当于始对象中的属性设置一个值! |
-->
<bean id="hello" class="com.hjt.pojo.Hello" >
<!--ref: 引用Spring容器中创建好的对象
value :具体的值。基本数据类型!
-->
<property name="str" value="Spring"/>
</bean>
<bean id="UserServiceImpl2" class="com.hjt.service.UserServiceImpl">
<property name="userdao" ref="Sqlserver"/>
</bean>
</beans>
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl UserServiceImpl = (com.hjt.service.UserServiceImpl) context.getBean("UserServiceImpl");
UserServiceImpl.getUser();
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Hello hello = (Hello)context.getBean("hello");
System.out.println(hello.toString());
3、IOC创建对象的方式
1、使用无参构造创建对象,默认!
必须有无参构造,不然会报错!
<bean id="hello" class="com.hjt.pojo.Hello" >
<property name="str" value="Spring"/>
</bean>
2、使用有参构造创建方法:
public User(String name) {
this.name = name;
System.out.println("User的有参构造");
}
//第一种,下标赋值
<bean id="user" class="com.hjt.pojo.User">
<constructor-arg index="0" value="何*~"/>
</bean>
//第二种,通过类型创建,不建议使用。
<bean id="user" class="com.hjt.pojo.User">
<constructor-arg type="java.lang.String" value="何*三号"/>
</bean>
//第三种,直接通过参数名创建bean
<bean id="user" class="com.hjt.pojo.User">
<constructor-arg name="name" value="何*四号"/>
</bean>
只要有bean,扫描xml之后容器中所有的对象都被实例化都被创建对象了,并且只创建一个实例,new几个相同的user都是一样的。
User user = (User)context.getBean("user");
User user2 = (User)context.getBean("user");
user==user2---------->true
4、Spring配置
4.1、别名
<bean id="user" class="com.hjt.pojo.User">
<constructor-arg name="name" value="何*四号"/>
</bean>
<alias name="user" alias="ssasasa"/>
User user = (User)context.getBean("user");
user.show();
User user1 = (User)context.getBean("ssasasa");
user1.show();
//User的有参构造
//name=何*四号
//name=何*四号
4.2、Bean的配置
id:bean的唯一标识符,也就是相当于我们学的对象名
class:bean对象所对应的全限定名:包名+类型
name:也是别名
<bean id="userT" class="com.hjt.pojo.User" name="user2,u2"><!--,和空格和;分隔都可以-->
</bean>
User user1 = (User)context.getBean("user2");
user1.show();
name=null
User user1 = (User)context.getBean("u2");
user1.show();
name=null
4.3、import
import一般用于团队开发使用,可将多个配置文件,导入合并一个。
<import resoure="bean.xml"/>
4.4、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="..." class="..."> (1) (2)
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
5、DI依赖注入
5.1、构造器注入
前面已经说过
5.2、Set方式注入【重点】
1.依赖注入:set注入!
*依赖:bean对象的创建依赖于容器!
*注入:bean对象中的所有属性,由容器来注入!
【环境搭建】
1.复杂类型
public class Address {
private String addr;
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
@Override
public String toString() {
return "Address{" +
"addr='" + addr + '\'' +
'}';
}
}
2.真实测试对象
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
3.beans.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="address" class="com.atctbu.hjt.Address">
<property name="addr" value="重庆"/>
</bean>
<bean id="student" class="com.atctbu.hjt.Student">
<!--第一种,普通值注入,value-->
<property name="name" value="何*"/>
<!--第二种,Bean注入,因为是引用型,所以是ref-->
<property name="address" ref="address"/>
<!--第三种,数组注入-->
<property name="books">
<array>
<value>Java从入门到入土</value>
<value>Web从入门到入土</value>
<value>Spring从入门到入土</value>
</array>
</property>
<!--第四种,List注入-->
<property name="hobbys">
<list>
<value>敲代码</value>
<value>听歌</value>
<value>看电影</value>
</list>
</property>
<!--第四种,Map注入-->
<property name="card">
<map>
<entry key="身份证" value="123456789"/>
<entry key="银行卡" value="987654321"/>
</map>
</property>
<!--第五种,Set注入-->
<property name="games">
<set>
<value>LOL</value>
<value>CF</value>
<value>CS</value>
</set>
</property>
<!--第六种,null值注入-->
<property name="wife">
<null/>
</property>
<!--第七种,properties注入
key=value
-->
<property name="info">
<props>
<prop key="姓名">何*</prop>
<prop key="学号">2018131224</prop>
<prop key="性别">男</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</beans>
4.测试类
public class Mytest {
public static void main(String[] args) {
ApplicationContext content = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student)content.getBean("student");
System.out.println(student.getName());
System.out.println(student.toString());
}
}
/*何*
Student{name='何*',
address=Address{addr='重庆'},
books=[Java从入门到入土, Web从入门到入土, Spring从入门到入土],
hobbys=[敲代码, 听歌, 看电影],
card={身份证=123456789, 银行卡=987654321},
games=[LOL, CF, CS], wife='null',
info={学号=2018131224, 性别=男, password=123456, 姓名=何*, username=root}}
*/
5.3、拓展方式注入
1.p命名空间注入:xmlns:p=“http://www.springframework.org/schema/p”
<?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">
<!--p命令注入可以直接注入属性的值:property-->
<bean id="user" class="com.atctbu.hjt.User" p:name="何*" p:age="21"/>
</beans>
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user",User.class);
System.out.println(user);
}
User{name='何*', age=21}
2.c命名空间注入:xmlns:c=“http://www.springframework.org/schema/c”
<!--p命令注入可以直接注入属性的值:property-->
<bean id="user" class="com.atctbu.hjt.User" p:name="何*" p:age="21"/>
<!--c命令注入可以通过构造器(有参构造)注入属性的值:construct-args-->
<bean id="user2" class="com.atctbu.hjt.User" c:name="张三" c:age="18"/>
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user",User.class);
User user2 = context.getBean("user2",User.class);
System.out.println(user);
System.out.println(user2);
}
User{name='何*', age=21}
User{name='张三', age=18}
5.4、Bean作用域
创建 bean 定义时,将创建一个配方来创建该 bean 定义所定义的类的实际实例。 bean 定义是配方的想法很重要,因为它意味着与类一样,您可以从一个配方中创建许多对象实例。
您不仅可以控制要插入到从特定 bean 定义创建的对象中的各种依赖项和配置值,还可以控制从特定 bean 定义创建的对象的范围。这种方法功能强大且灵活,因为您可以选择通过配置创建的对象的范围,而不必在 Java 类级别上烘烤对象的范围。可以将 Bean 定义为部署在多个范围之一中。 Spring 框架支持六个范围,其中只有在使用网络感知ApplicationContext
时才可用。您也可以创建[自定义范围]。
Scope | Description |
---|---|
singleton | (默认)将每个 Spring IoC 容器的单个 bean 定义范围限定为单个对象实例。 |
prototype | 将单个 bean 定义的作用域限定为任意数量的对象实例。 |
request | 将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个在单个 bean 定义后面创建的 bean 实例。仅在可感知网络的 Spring ApplicationContext 中有效。 |
session | 将单个 bean 定义的范围限定为 HTTP Session 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
application | 将单个 bean 定义的范围限定为ServletContext 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
websocket | 将单个 bean 定义的范围限定为WebSocket 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
**1.单例模式(Spring默认机制)**单线程使用得多
<bean id="user2" class="com.atctbu.hjt.User" c:name="张三" c:age="18" scope="singleton"/>
User user = context.getBean("user",User.class);
User user2 = context.getBean("user2",User.class);
System.out.println(user==user2);
true
**2.原型模式:每次从容器中get 的时候都会产生一个新对象!**多线程使用得多
<bean id="user2" class="com.atctbu.hjt.User" c:name="张三" c:age="18" scope="prototype"/>
User user = context.getBean("user",User.class);
User user2 = context.getBean("user2",User.class);
System.out.println(user==user2);
false
3.其余的 request、session、application、这些个只能在web开发中使用到
6、Bean的自动装配
-
自动装配是Spring满足bean依赖的一种方式!
-
Spring会在上下文中自动寻找,并自动给bean装配属性!
在Spring中有三种装配的方式
1.在xml中显示配置
2.在java中显示配置
3.隐式的自动装配bean【最重要的】
6.1、测试
1.环境搭建:一个人有两个宠物:
<?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="cat" class="com.atctbu.hjt.Cat"/>
<bean id="dog" class="com.atctbu.hjt.Dog"/>
<bean id="people" class="com.atctbu.hjt.People">
<property name="name" value="何*"/>
<!-- 引用型:ref-->
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
</beans>
public class People {
private Cat cat;
private Dog dog;
private String name;
public class mytest {
@Test
public void test1(){
ApplicationContext Context = new ClassPathXmlApplicationContext("beans.xml");
People people = Context.getBean("people", People.class);
people.getCat().shout();
people.getDog().shout();
}
}
miao~
wang~
6.2、ByName和ByType自动装配
**byName:**会自动在容器上下文寻找,和自己对象set方法后面的值对应的beanid
必须保证所有bean 的id唯一,并且这个bean需要和自动注入的属性的set方法一致!
<bean id="cat" class="com.atctbu.hjt.Cat"/>
<bean id="dog" class="com.atctbu.hjt.Dog"/>
<!-- byName:会自动在容器上下文寻找,和自己对象set方法后面的值对应的beanid-->
<bean id="people" class="com.atctbu.hjt.People" autowire="byName">
<property name="name" value="何*"/>
</bean>
还是能找到显示出
miao~
wang~
--------------------------------------------------------------------------
<bean id="cat" class="com.atctbu.hjt.Cat"/>
<bean id="dog222" class="com.atctbu.hjt.Dog"/>
<!-- byName:会自动在容器上下文寻找,和自己对象set方法后面的值对应的beanid-->
<bean id="people" class="com.atctbu.hjt.People" autowire="byName">
<property name="name" value="何*"/>
</bean>
狗的名字被改了,就找不到了,报空指针异常
**byType:**必须保证类型全局唯一,才能自动装配
必须保证所有bean 的class唯一,并且这个bean需要和自动注入的属性的类型一致!
<bean id="cat" class="com.atctbu.hjt.Cat"/>
<bean id="dog222" class="com.atctbu.hjt.Dog"/>
<!--byType:会自动在容器上下文寻找,和自己对象属性类型相同的bean-->
<bean id="people" class="com.atctbu.hjt.People" autowire="byType">
<property name="name" value="何*"/>
</bean>
狗的名字被改了,也能找到显示出,甚至不用命名id也可以找到
<bean class="com.atctbu.hjt.Cat"/>
<bean class="com.atctbu.hjt.Dog"/>
miao~
wang~
6.3、使用注解自动装配
JDK1.5支持注解:Spring2.5就开始支持注解了
要使用注解须知:
-
导入约束;xmlns:context=“http://www.springframework.org/schema/context”
-
配置注解的支持;<context:annotation-config/>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!--导入context-->
xmlns:context="http://www.springframework.org/schema/context"
<!--导入aop-->
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
<!--导入context-->
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
<!--导入aop-->
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="cat" class="com.atctbu.hjt.Cat"/>
<bean id="dog222" class="com.atctbu.hjt.Dog"/>
<bean id="people" class="com.atctbu.hjt.People"/>
<!--开启注解支持-->
<context:annotation-config/>
</beans>
6.3.1、@Autowaired、@Qualifier(value="")、@Resource、@Nullable
前提是名字相同,自动导入(名字不同好像也可以)
直接在属性上使用即可!也可以在set方式上使用!
使用Autowired我们可以不用编写Set方法了,前提是你在这个自动装配的属性在IOC容器中存在,且符合名字byname!
@Autowaired(required = false)//如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空。
@Qualifier(value=“dog222”) 当使用@Autowired自动装配的环境比较复杂(有多个猫猫狗狗的时候),自动装配无法通过一个注解【@Autowired】完成的时候,使用@Qualifier(value=“dog222”),去配合Autowired的使用,给它指定一个实现的值(bean对象)
@Nullable:字段标记了这个注解,说明这个字段可以为null;
@Resource:先通过名字查找,名字找不到根据类型查找,都找不到就报错,(有多个猫猫狗狗好像不行)@Resource(name = “cat2”),可以指定找哪个
小结:
@Resource和@ Autowired的区别:
● 都是用来自动装配的,都可以放在属性字段上
● @ Autowired通过byType的方式实现,而且必须要求这个对象存在!
● @ Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!● 执行顺序不同:@ Autowired通过byType的方式实现。
public class People {
@Resource(name = "cat2")
private Cat cat;
@Autowired
Qualifier(value="dog222")
private Dog dog;
private String name;
public class mytest {
@Test
public void test1(){
ApplicationContext Context = new ClassPathXmlApplicationContext("beans.xml");
People people = Context.getBean("people", People.class);
people.getCat().shout();
people.getDog().shout();
}
}
//能显示出结果
miao~
wang~