Spring核心(Core模块):IOC

1. IOC容器初理解

解决对象的创建以及对象之间的依赖关系。

主要学习如何得到IOC容器,IOC容器如何创建对象,如何解决对象之间的依赖关系,以及IOC的具体细节

Spring的核心思想之一就是IOC(控制反转)

控制反转的意思:对象的创建交给外部容器完成

  • Spring使用控制反转来实现对象不用再程序中写死
  • 控制反转将对象由我们创建交给容器创建

依赖注入:解决对象之间的依赖关系

  • Spring使用依赖注入来实现对象之间的依赖关系

2. 得到IOC容器

IOC容器可以分为两种接口

  • Bean工厂,BeanFactory———功能简单
  • 应用上下文,ApplicationContext———功能强大

2.1 通过Resoure获取Bean工厂

  • 加载Spring的资源文件
  • 获取IOC容器
  1. ClassPathXmlApplicationContext context = new
  2. ClassPathXmlApplicationContext("applicationContext.xml");
  3. //在执行getbean时,user对象已经通过无参构造创建成功了。
  4. User user = (User) context.getBean("user");

2.2 直接通过ClassPathXmlApplicationContext对象来获取

  1. // 加载配置文件
  2. ClassPathResource classPathResource = new ClassPathResource("applicationContext.xml");
  3. // IOC容器创建对象
  4. XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(classPathResource);

3. IOC容器创建对象及属性注入

在Spring中总体可以通过三种方式来创建对象

IOC容器 - 图1

3.1 XML配置方式

  1. 首先我们需要一个类User.class
  1. public class User {
  2. private String name;
  3. private int age;
  4. public User() {
  5. System.out.println("我是User,被无参构造器创建了。。。");
  6. }
  7. public User(String name, int age) {
  8. this.name = name;
  9. this.age = age;
  10. }
  11. public String getName() {
  12. return name;
  13. }
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17. public int getAge() {
  18. return age;
  19. }
  20. public void setAge(int age) {
  21. this.age = age;
  22. }
  23. public void show() {
  24. System.out.println("name" + name);
  25. }
  26. }
  1. 以前我们都是通过new User() 的方式来创建对象
    现在通过IOC容器来创建对象,我们只需要在applicationContext.xml核心配置文件中配置对应的信息即可
  1. User user = new User();
  1. 通过IOC容器来获取创建的对象
  1. <!--
  2. 使用bean节点来创建对象
  3. id属性标识对象
  4. class属性代表要创建的对象的全类名
  5. -->
  6. <bean id="hello" class="com.xiaojian.pojo.User"></bean>
  1. 从控制台打印的结果我们可以看出来,IOC是通过无参构造函数的方式进行创建对象,IOC一般有三种创建对象的方式

IOC容器 - 图2

1. 有参构造器创建对象

  1. 首先Javabean需要提供带参数的构造函数
  1. public User(String name, int age) {
  2. this.name = name;
  3. this.age = age;
  4. }
  1. 关键点,配置applicationContext.xml文件,三种方式进行属性的注入,并且可以混合使用
    有参构造器我们通过<constructor-arg>标签来完成配置。
  1. <!-- 构造器注入
  2. 通过有参的构造方法 通过参数index的下标进行设置 -->
  3. <bean id="userT" class="com.xiaojian.pojo.UserT">
  4. <constructor-arg index="0" value="张三"/>
  5. </bean>
  6. <!--通过有参的构造方法 通过参数的名字 -->
  7. <bean id="userT" class="com.xiaojian.pojo.UserT">
  8. <constructor-arg name="name" value="张三"/>
  9. </bean>
  10. <!--通过有参的构造方法 通过参数的类型 -->
  11. <bean id="userT" class="com.xiaojian.pojo.UserT">
  12. <constructor-arg type="java.lang.String" value="张三"/>
  13. </bean>
  1. 获取结果
  1. @Test
  2. public void test2() {
  3. ClassPathXmlApplicationContext context = new
  4. ClassPathXmlApplicationContext("applicationContext.xml");
  5. //在执行getbean时,user对象已经通过无参构造创建成功了。
  6. UserT user = (UserT) context.getBean("userT");
  7. System.out.println(user);
  8. // 容器创建对象和我们创建对象的方式一样
  9. UserT userT = new UserT();
  10. System.out.println(userT);
  11. }

IOC容器 - 图3

2. 工厂创建对象

1. 静态工厂方法
  1. 首先使用一个工厂的静态方法返回一个对象
  1. public class BeanFactory {
  2. public static User getBean(){
  3. return new User();
  4. }
  5. }
  1. 配置文件中使用工厂的静态方法返回对象
  1. <bean id="user3" class="com.xiaojian.pojo.BeanFactory" factory-method="getBean">
  2. </bean>
  1. 测试结果
  1. @Test
  2. public void test3() {
  3. ClassPathXmlApplicationContext context = new
  4. ClassPathXmlApplicationContext("applicationContext.xml");
  5. User user = (User) context.getBean("user3");
  6. System.out.println(user);
  7. }
  8. // 我是User,被无参构造器创建了。。。
  9. // User{name='null', age=0}

2.非静态工厂方法
  1. 和静态工厂相同使用工厂的非静态方法返回一个对象
  1. public class BeanFactory {
  2. public User getBean(){
  3. return new User();
  4. }
  5. }
  1. 配置文件中使用工厂的非静态方法返回对象
  1. <!--首先创建工厂对象-->
  2. <bean id="factory" class="com.xiaojian.pojo.BeanFactory"/>
  3. <!--指定工厂对象和工厂方法-->
  4. <bean id="user" class="com.xiaojian.pojo.User" factory-bean="factory" factory-method="getBean">
  1. 测试结果相同

3. xml方式依赖注入

IOC容器 - 图4

构造器注入在前面已经说过,下面主要介绍属性注入

1. 常量注入
  1. <!--2.常量注入-->
  2. <bean id="student" class="com.xiaojian.pojo.Student">
  3. <property name="name" value="李四"/>
  4. </bean>

测试类

  1. @Test
  2. public void test4(){
  3. ClassPathXmlApplicationContext context = new
  4. ClassPathXmlApplicationContext("applicationContext.xml");
  5. Student student = (Student) context.getBean("student");
  6. System.out.println(student.getName());
  7. }

2. bean注入
  1. <!--3.bean注入-->
  2. <bean id="addr" class="com.xiaojian.pojo.Address">
  3. <property name="address" value="上海"/>
  4. </bean>
  5. <bean id="student1" class="com.xiaojian.pojo.Student">
  6. <property name="name" value="王五"/>
  7. <property name="address" ref="addr"/>
  8. </bean>

测试类

  1. @Test
  2. public void test4(){
  3. ClassPathXmlApplicationContext context = new
  4. ClassPathXmlApplicationContext("applicationContext.xml");
  5. Student student = (Student) context.getBean("student1");
  6. System.out.println(student.getAddress().getAddress());
  7. System.out.println(student.getName());
  8. }

3. 数组注入
  1. <!--4.数组注入-->
  2. <bean id="student2" class="com.xiaojian.pojo.Student">
  3. <property name="books">
  4. <array >
  5. <value>红楼梦</value>
  6. <value>三国演绎</value>
  7. <value>西游记</value>
  8. <value>水浒传</value>
  9. </array>
  10. </property>
  11. </bean>

测试类

  1. @Test
  2. public void test4(){
  3. ClassPathXmlApplicationContext context = new
  4. ClassPathXmlApplicationContext("applicationContext.xml");
  5. Student student = (Student) context.getBean("student2");
  6. System.out.println(student.getAddress().getAddress());
  7. System.out.println(student.getName());
  8. student.show();
  9. }

4. List注入
  1. <property name="hobbys">
  2. <list>
  3. <value>听歌</value>
  4. <value>打球</value>
  5. </list>
  6. </property>

5. map注入
  1. <property name="card">
  2. <map>
  3. <entry key="邮政" value="34234234234312"/>
  4. <entry key="招商" value="4323465474523"/>
  5. </map>
  6. </property>

6. set注入
  1. <property name="games">
  2. <set>
  3. <value>LOL</value>
  4. <value>BOB</value>
  5. <value>COC</value>
  6. </set>
  7. </property>

7. Null注入
  1. <property name="wife"><null/></property>

8.properties注入
  1. <property name="info">
  2. <props>
  3. <prop key="学号">20190604</prop>
  4. <prop key="性别"></prop>
  5. <prop key="姓名">小明</prop>
  6. </props>
  7. </property>

所有属性的测试类

  1. @Test
  2. public void test4(){
  3. ClassPathXmlApplicationContext context = new
  4. ClassPathXmlApplicationContext("applicationContext.xml");
  5. Student student = (Student) context.getBean("student4");
  6. // System.out.println(student.getAddress().getAddress());
  7. //System.out.println(student.getName());
  8. student.show();
  9. }

测试结果

  1. name=王五,address上海,books=
  2. <<红楼梦>>
  3. <<三国演绎>>
  4. <<西游记>>
  5. <<水浒传>>
  6. 爱好:[听歌, 打球]
  7. card:{邮政=34234234234312, 招商=4323465474523}
  8. games:[LOL, BOB, COC]
  9. wife:null
  10. info:{学号=20190604, 性别=男, 姓名=小明}

9. P命名空间和C命名空间的注入
  1. p命名空间注入需在头文件中导入约束
  1. //导入约束 xmlns:p="http://www.springframework.org/schema/p"
  2. <!--p的命名空间 -->
  3. <bean id="user1" class="com.xiaojian.pojo.User"
  4. p:age="24" p:name="小贱"
  5. />
  1. c命名空间也要在头文件添加约束
  1. //导入约束 xmlns:c="http://www.springframework.org/schema/c"
  2. <!--c的命名空间 -->
  3. <bean id="user2" class="com.xiaojian.pojo.User"
  4. c:age="24" c:name="小贱"
  5. />

若此时User对象没有有参构造会爆红。

也就是说c命名空间就是构造器注入

3.2 @component等衍生注解配置方法

1. bean的实例化

  1. 在使用注解进行bean的实例化的时候,首先需要在配置文件中进行开启注解扫描的配置
  1. <!--开启注解的扫描 扫描pojo包下面的所有类-->
  2. <context:component-scan base-package="com.xiaojian"/>
  3. <!--只会扫描属性上的注解-->
  4. <context:annotation-config/>
  1. 使用注解创建对象
  1. @Component(value = "userServiceImpl") //相当于在配置文件中<bean id="computer" class="……"></bean>
  2. @Scope(value = "prototype") // 配置创建对象是否以单例模式进行创建
  3. public class UserServiceImpl implements UserService {
  4. public User queryUser() {
  5. User user = new User();
  6. user.setAge(11);
  7. return user;
  8. }
  9. }

在需要实例化的类的类名上面加上@Component 注解来进行标识,value的值就相当于在配置文件中进行配置时bean标签的id属性的值,用于对象的创建

2. 创建对象的四个注解

  1. @Component
  2. @Controller //web层中使用
  3. @Service   //业务层
  4. @Repository //持久层

这四个注解目前的功能都是一样的,注解名的不同为了能够让标记类本身的用途更加清晰,Spring在后续的版本中会对其加强

3. 使用注解注入对象属性

  1. 在开发中,我们经常会遇到在一个类中调用另一个类的情况(控制层调用业务逻辑层),这就属于注入了对象属性,现在我们学习使用注解的方式注入对象属性。
  1. @Component(value = "userDaoImpl")
  2. public class UserDaoImpl implements UserDao {
  3. @Autowired // 自动装配,根据类名称去找相应的类来创建对象
  4. private UserService userService;
  5. public User queryUser() {
  6. User user = userService.queryUser();
  7. user.setName("xiaoxin ");
  8. return user;
  9. }
  10. }

3.1 两种对象属性注入的注解
  1. 使用 @Autowired 注解进行自动装配,不需要指定要注入的对象的value值,自动的根据类名去寻找对应的类来创建对象并进行对象属性的注入。
  2. 使用 @Resource(name=”userDao”),需要指定需要创建的对象的名字,这里的name对应@Component注解中的value的值,使用这个注解能够根据我们所指定的对象名准确创建出我们所需要的对象。
  1. @Resource(name = "userServiceImpl") // name属性值写使用注解创建对象时的value中的值
  2. private UserService userService;

3.3 配置文件和注解混合使用

  1. 创建对象使用配置文件的方式
  1. public class UserDaoImpl implements UserDao {
  2. public void add() {
  3. System.out.println("注解,配置文件混合版");
  4. }
  5. }
  1. <bean id="userDao" class="com.xiaojian.Dao.UserDaoImpl"/>
  1. 注入属性使用注解的方式在UserServiceImpl中引用UserDaouserDaoImpl类
  1. @Component(value = "userServiceImpl")
  2. public class UserServiceImpl implements UserService {
  3. @Resource(name = "userDao")
  4. private UserDao userDao;
  5. public void add() {
  6. userDao.add();
  7. }
  8. }
  1. 测试类
  1. @Test
  2. public void test3() {
  3. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  4. UserService userService = (UserService) context.getBean("userServiceImpl");
  5. userService.add();
  6. }
  1. 测试结果
  1. 注解,配置文件混合版

3.4 Java的配置方式

后续。。。。