IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring之ioc控制反转 -> 正文阅读

[Java知识库]Spring之ioc控制反转

Spring的IOC思想

1.IOC:控制反转

IOC 是指在程序开发中,实例的创建不在由调用者管理,而是由Spring容器创建。
容器会控制对象之间的关系,而不是由程序代码直接控制。
因此控制权由程序代码转移到了Spring容器中。
控制权发生了反转,这就是Spring的IOC思想。

准备工作:修改pom文件

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.15.RELEASE</version>
    </dependency>

刷新maven即可添加。

2.使用bean标签:

先创建一个preson类

package com.lr.spring.po;

public class Person {
    //属性
    private Integer id;
    private String name;
    private double sal;
    //无参构造方法
    public Person (){
        System.out.println("创建person对象");
    }
}

配置文件

<?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">
<!--
beans是spring中的根标签,在bean标签中配置自己需要的对象
1.bean在spring中相当于java中的对象,需要把该对象对应的类配置到容器中
2.id="":标识,相当于对象名,唯一
3.class="包名.类名(即全限定名)"  包名.类名通过反射创建该类的对象,不能写接口名
  -->
    <bean id="person1" class="com.lr.spring.po.Person"></bean>
<!--  把Person类纳入到spring管理中,当程序执行(默认),在spring容器,创建一个Preson类的对象preson1(反射)  -->
</beans>

?测试类

package com.lr.spring;

import com.lr.spring.po.Person;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest{
    @Test
    public void test01(){
        BeanFactory factory = new ClassPathXmlApplicationContext("application.xml");
        Person person = (Person)factory.getBean("person1");
        System.out.println(person);
        //单例模式:对象person是唯一的
        Person person2 = (Person)factory.getBean("person1");
        System.out.println(person2);
    }
}

测试结果

3.:单例模式与多例模式

单例模式:singleton

默认值,单例(不管任何人,多少人过来访问,拿到的都是同一个对象)

    <bean id="person1" class="com.lr.spring.po.Person" scope="singleton"></bean>

?多例模式:prototype

多例,懒加载(延迟加载),读取配置文件的时候不创建对象,只有调用getBean()方法的时候,才创建对象

    <bean id="person1" class="com.lr.spring.po.Person" scope="prototype"></bean>

加入多例模式后,测试结果发生的变化,两个对象地址不一样了

?

4.懒加载

beans是spring中的根标签,在bean标签中配置自己需要的对象
1.bean在spring中相当于java中的对象,需要把该对象对应的类配置到容器中
2.id="":标识,相当于对象名,唯一
3.class="包名.类名(即全限定名)"  包名.类名通过反射创建该类的对象,不能写接口名
  -->
    <bean id="person1" class="com.lr.spring.po.Person" scope="prototype" lazy-init="default"></bean>
<!--  把Person类纳入到spring管理中,当程序执行(默认),在spring容器,创建一个Preson类的对象preson1(反射)  -->
<!--scope="prototype"/"singleton":控制spring容器创建的对象是单例还是多例
singleton:默认值,单例(不管任何人,多少人过来访问,拿到的都是同一个对象)
prototype:多例,懒加载(延迟加载),读取配置文件的时候不创建对象,只有调用getBean()方法的时候,才创建对象
lazy-init="true"/"default"/"false":主要是针对单例模式的
true:懒加载(延迟加载),只有使用的时候才真正创建该类对象
default/false:不懒加载,读取配置文件时就立刻创建对象,default是默认值
-->

?ioc实例

1.创建User类

package com.lr.spring.po;

import java.io.Serializable;

public class User implements Serializable {
    public Integer id;
    private String name;
    private String password;

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

2.写入配置文件,用bean进行管理

<?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="user1" class="com.lr.spring.po.User"></bean>
    <bean id="user2" class="com.lr.spring.po.User"></bean>
    <bean id="user3" class="com.lr.spring.po.User"></bean>
</beans>

3.测试程序

测试ApplicationContext()中的几个方法

package com.lr.spring;

import com.lr.spring.po.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest{
    @Test
    public void test01(){
        //ApplicationContext在实际开发中取代了BeanFactory,功能更加枪法,而且有很多其他功能
        ApplicationContext factory = new ClassPathXmlApplicationContext("application.xml");
        User user1=(User)factory.getBean("user1");
        System.out.println(user1);
        //getBeanDefinitionCount()可以查配置文件里有多少个对象
        int count = factory.getBeanDefinitionCount();
        System.out.println("对象的个数:"+count);
        //getBeanDefinitionNames():获取对象的名字
        String[] names =factory.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}
//通过程序在初始化的时候,导入Bean配置文件,然后得到Bean实例。
        ApplicationContext factory2 =new FileSystemXmlApplicationContext("D:\\code\\spring02\\src\\main\\resources\\application.xml");
        User user1 = (User) factory2.getBean("user1");
        System.out.println(user1);

添加其他类

添加date类

1.配置文件

注意,这里需要绝对路径,date类在其他包里

<?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="user1" class="com.lr.spring.po.User"></bean>
    <bean id="user2" class="com.lr.spring.po.User"></bean>
    <bean id="user3" class="com.lr.spring.po.User"></bean>
    <bean id="date1" class="java.util.Date"></bean>
</beans>

2.测试程序?

ApplicationContext factory = new ClassPathXmlApplicationContext("application.xml"); 
Date date1=(Date) factory.getBean("date1");
      System.out.println(date1);

?

在User加入多参构造方法,与tostring方法,测试默认调用无参构造方法?

?

工厂模式

如果想调用多参构造方法呢?使用工厂模式:写一个UserFactory类,提供方法

1.静态方法创建对象

package com.lr.spring.factory;

import com.lr.spring.po.User;

public class UserFactory {
    //静态方法创建对象(3参构造方法)
    public static User getUserStaticInstance(){
        System.out.println("通过spring调用工厂中的静态方法创建3参User对象:");
        return new User(1111,"龙傲天","1380341");
    }
}

2.配置文件

!--  通过spring调用工厂中的静态方法创建3参User对象  -->
<!--   静态方法 -->
    <bean id="user4" class="com.lr.spring.factory.UserFactory" factory-method="getUserStaticInstance"></bean>

3测试文件?

    @Test
    public void test02(){
        ApplicationContext app=new ClassPathXmlApplicationContext("application.xml");
        User user=(User) app.getBean("user4");
        System.out.println(user);
    }

1.实例方法创建对象?

//实例方法创建对象
    public User getUserInstance(){
        System.out.println("通过spring调用工厂中的静态方法创建3参User对象");
        return new User(2222,"唐三","123456");
    }

?2.配置文件

<!--  使用实例方法  -->
    <bean id="factory" class="com.lr.spring.factory.UserFactory"></bean>
    <bean id="user5" factory-bean="factory" factory-method="getUserInstance"></bean>

?3测试程序

   public void test02(){
        ApplicationContext app=new ClassPathXmlApplicationContext("application.xml");
//        User user=(User) app.getBean("user4");
//        System.out.println(user);
        User user=(User) app.getBean("user5");
        System.out.println(user);
    }

?

4. 补充bean标签属性

init属性(初始化)? ? ? ?destroy属性(销毁)

    <bean id="user1" class="com.lr.spring.po.User" init-method="init" destroy-method="destory"></bean>

测试初始化

?测试销毁方法

ps:需要用到实现类,因为ApplicationContext没有close()方法

 public void test03(){
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("application.xml");
//        User user=(User) app.getBean("user4");
//        System.out.println(user);
        User user=(User) app.getBean("user5");
        System.out.println(user);
        app.close();//关闭Spring容器
    }
}

?

?

使用构造方法创建bean对象

两种方法

通过name属性

通过下标

<?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对象-->
    <bean id="user1" class="com.lr.spring.po.User">
        <constructor-arg name="id" value="1003"></constructor-arg>
        <constructor-arg name="name" value="张三"></constructor-arg>
        <constructor-arg name="password" value="123456"></constructor-arg>
    </bean>
    <bean id="user2" class="com.lr.spring.po.User">
        <constructor-arg name="id" index="0" value="1004"></constructor-arg>
        <constructor-arg name="name" index="1" value="李四"></constructor-arg>
        <constructor-arg name="password" index="2" value="654321"></constructor-arg>
    </bean>

</beans>

测试程序

 @Test
    public void test03(){
        ApplicationContext factory = new ClassPathXmlApplicationContext("application2.xml");
        User user01=(User) factory.getBean("user1");
        System.out.println(user01);
        User user02=(User) factory.getBean("user2");
        System.out.println(user02);
    }

测试结果

 

两种方法都能创建对象

DI:依赖注入

DI—Dependency Injection,即依赖注入

是组件之间依赖关系由容器在运行期决定

我们只需要通过 简单的配置,无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,不需要关心具体的资源来自何处,由谁实现?

?

加入数据访问层dao与业务层service

面向接口编程:减少因为Dao层的改变,对业务层代码的修改.

1.业务逻辑

以前我们常用的业务逻辑

//UserService 
package com.lr.spring.service;

public interface UserService {
    void addUser();
}



//UserDao 
package com.lr.spring.dao;

public interface UserDao {
    void addUser();
}



//UserServiceImpl 
import com.lr.spring.dao.UserDaoImpl;

public class UserServiceImpl implements UserService {
    private UserDaoImpl userDao = new UserDaoImpl();
    @Override
    public void addUser() {
        System.out.println("调用UserDao,插入User对象");
        userDao.addUser();
    }
}



//UserDaoImpl 

package com.lr.spring.dao;

public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("Dao中输入User对象");
    }
}

2.人为实现?DI注入

spring可以做到更完美的解耦合,令dao层的改动完全不影响service层,我们需要修改serviceinpl

这个方法就是DI注入

人为实现DI注入代码,有三种方法

第一种:set注入

package com.lr.spring.service;

import com.lr.spring.dao.UserDao;
import com.lr.spring.dao.UserDaoImpl;

public class UserServiceImpl implements UserService {
//    private UserDaoImpl userDao = new UserDaoImpl();
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        System.out.println("调用UserDao,插入User对象");
        userDao.addUser();
    }
//通过set注入
    public static void main(String[] args) {
        UserServiceImpl userService=new UserServiceImpl();
        userService.setUserDao(new UserDaoImpl());
    }
}

Spring实现DI注入

第一种set注入

set 注入也叫设值注入是指,通过 setter 方法传入被调用者的实例。这种注入方式简单、直观,因而在
Spring 的依赖注入中大量使用。

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 name="userDao" class="com.lr.spring.dao.UserDaoImpl"></bean>
      <bean name="suerService" class="com.lr.spring.service.UserServiceImp
      <!--    property标签中的name参数跟set方法名字一一对应,跟属性名无关      -->
          <property name="userDao" ref="userDao"></property>
      </bean>

</beans>

?ps:property标签中的name参数跟set方法名字一一对应,跟属性名无关?

2.测试程序

@Test
    public void test04(){
        ApplicationContext factory = new ClassPathXmlApplicationContext("application3.xml");
        UserService userService=(UserService) factory.getBean("userService");
        userService.addUser();
    }

?

第二种:通过构造方法注入?

构造注入是指,在构造调用者实例的同时,完成被调用者的实例化。使用构造器设置依赖关系。
<!--  构造方法注入  -->
<!-- constructor-arg标签中的name参数跟构造方法中的参数名字名字一一对应,跟属性名无关 -->
    <bean name="userService" class="com.lr.spring.service.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao"></constructor-arg>
    </bean>

?

结果一模一样

ps:constructor-arg标签中的name参数跟构造方法中的参数名字名字一一对应,跟属性名无关

扩展?

新增两个dao实现类,我们使用set注入的方式

package com.lr.spring.dao;

public class UserMySQLDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("MySQLDa");
    }
}




package com.lr.spring.dao;

public class UserOracleDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("OracleDao");
    }
}

配置文件?

<bean name="userDao" class="com.lr.spring.dao.UserDaoImpl"></bean>
      <bean name="userMySQLDao" class="com.lr.spring.dao.UserMySQLDaoImpl"></bean>
      <bean name="userOracleDao" class="com.lr.spring.dao.UserOracleDaoImpl"></bean>

      <bean name="userService" class="com.lr.spring.service.UserServiceImpl">
        <property name="userDao" ref="userMySQLDao"></property>
      </bean>

?

如果我们的数据库换成MySQL只需修改配置文件property标签ref属性值为userMySQLDao即可。

第三种:自动注入?

对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为标签
设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属 性)。根据
自动注入判断标准的不同,可以分为两种:
byName :根据名称自动注入,跟set方法中的方法名对应
byType : 根据类型自动注入,跟属性的类型对应(只有一个的时候使用)

?

?

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-14 01:50:01  更:2022-01-14 01:52:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:24:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码