Spring中IoC容器和Bean

目录

IoC(Inversion of Control)控制反转思想

Spring技术对IoC思想的实现

DI(Dependency Injection)依赖注入

目标

最终效果

IoC入门案例

传统方法,不使用IoC思想调用dao层 

使用IoC思想调用dao层

第一步:导入Spring坐标

第二步:创建Spring配置文件

 第三步:初始化IoC容器,并通过容器来获取bean对象

不使用IoC思想调用service层

使用IoC思想调用service层

总结:如何将对象交给spring容器管理

Bean的基础配置

标签中的name属性:给一个bean变量起别名 

标签中的scope属性:控制bean变量是单例还是多例,默认是单例(多次从容器获取的bean对象是同一个)

 适合交给IoC容器管理的bean

不适合交给IoC容器管理的bean

 Bean的实例化

第一种:通过无参构造,初始化IoC容器时就会调用所有bean对象的无参构造方法,创建每个bean对象

第二种:通过静态工厂

第三种:通过实例化工厂类

 依赖注入方式

 第一种setter注入

第二种:构造器注入


IoC(Inversion of Control)控制反转思想

        使用对象时,由主动的new产生对象转换成由外部提供对象,此过程对象控制权由程序转移到外部,此思想称为控制反转。

Spring技术对IoC思想的实现

        spring提供了一种容器,叫做IoC容器,用来充当IoC思想的"外部”

        IoC容器负责对象的创建,初始化一系列工作,被创建或被管理的对象在IoC容器中都叫做Bean

DI(Dependency Injection)依赖注入

        在容器中建立bean和bean之间的依赖关系的整个过程,称为依赖注入

目标

  1.          在IoC容器中管理bean
  2.         在IoC容器中将有依赖关系bean进行绑定(DI)

最终效果

        使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean都已经绑定了所有的依赖关系

IoC入门案例

传统方法,不使用IoC思想调用dao层 

 

public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("bookDao save");
    }
}

 不使用IoC思想(自己new一个对象,缺点:接口与实现类的耦合性太高)


/*
传统方法
 */
public class Book {
    public static void main(String[] args) {
        BookDao bookDao=new BookDaoImpl();
        bookDao.save();
    }
}

使用IoC思想调用dao层

第一步:导入Spring坐标

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

第二步:创建Spring配置文件

<?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="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    id是为这个实现类起别名
</beans>

 第三步:初始化IoC容器,并通过容器来获取bean对象

public class App {
    public static void main(String[] args) {
        //初始化容器,加载配置文件
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");//从容器中new一个id为bookDao的实现类对象,并依赖注入到这
        bookDao.save();
    }
}

我们可以发现使用IoC思想可以把接口和实现类的耦合度降低很多,由于这个实现类在IoC容器里注册为了Bean对象,所以我们可以直接通过容器来获取接口对应的Bean对象(实现类对象)

不使用IoC思想调用service层

BookServiceImpl

public class BookServiceImpl implements BookService {
    BookDao bookDao;
    @Override
    public void save() {
        System.out.println("bookService");
        bookDao.save();
    }

    @Override
    public void setBookDao(BookDao bookDao) {
        this.bookDao=bookDao;
    }
}
public class Test {
    public static void main(String[] args) {
        BookService bookService=new BookServiceImpl();
        BookDao bookDao=new BookDaoImpl();
        bookService.setBookDao(bookDao);
        bookService.save();
    }
}

使用IoC思想调用service层

springContext.xml文件的配置,由于bookServiceImpl实现类里有一个dao层的成员变量,所以在这个<bean>中要给这个dao层的成员变量单独配置

  <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl">
<!--        name属性是实现类中dao层的成员变量的名字
            ref属性是id-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>

调用

public class App {
    public static void main(String[] args) {
        //初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

 

总结:如何将对象交给spring容器管理

  • 配置文件使用<bean>标签配置
  • 初始化IoC容器,加载配置文件 

Bean的基础配置

<bean>标签中的name属性:给一个bean变量起别名 

<bean id="bookService" name="service service2" class="com.hhh.service.impl.BookServiceImpl">
<!--        name属性是实现类中dao层的成员变量的名字
            ref属性是id-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>

如图:给bookServiceImpl实现类Bean对象起了两个别名,可以使用空格,也可以使用, ; 这两种符号来间隔别名 

public class App {
    public static void main(String[] args) {
        //初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        //BookService bookService = (BookService) ctx.getBean("bookService");
        BookService bookService = (BookService) ctx.getBean("service");
        bookService.save();
    }
}

<bean>标签中的scope属性:控制bean变量是单例还是多例,默认是单例(多次从容器获取的bean对象是同一个)

public class App {
    public static void main(String[] args) {
        //初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        //BookService bookService = (BookService) ctx.getBean("bookService");
        BookService bookService1 = (BookService) ctx.getBean("service");
        BookService bookService2 = (BookService) ctx.getBean("service");
        System.out.println(bookService1);
        System.out.println(bookService2);
         //com.hhh.service.impl.BookServiceImpl@4c1d9d4b
        //com.hhh.service.impl.BookServiceImpl@4c1d9d4b

    }
}

可以这两个Bean对象都是同一个,接下来我们修改一下

 <bean id="bookService" name="service service2" class="com.hhh.service.impl.BookServiceImpl"
    scope="prototype"
    >
<!--        name属性是实现类中dao层的成员变量的名字
            ref属性是id-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>

可以发现修改之后这两个bean对象就是不同的 

 适合交给IoC容器管理的bean

  • dao层对象
  • service层对象
  • web层对象
  • 工具对象

不适合交给IoC容器管理的bean

封装实体的域对象(实体类)

 Bean的实例化

第一种:通过无参构造,初始化IoC容器时就会调用所有bean对象的无参构造方法,创建每个bean对象

第二种:通过静态工厂

创建静态工厂类

public class StaticBookDaoFactory {
    public static BookDao getBookDao(){
        return new BookDaoImpl();
    }

}

配置

 <bean id="bookDao" class="com.hhh.factory.StaticBookDaoFactory" factory-method="getBookDao"> </bean>

通过factory-method属性来指定通过静态工厂的静态成员方法来返回的对象与id="bookDao"对应

相当于:

BookDao bookDao= StaticBookDaoFactory.getBookDao();

第三种:通过实例化工厂类

public class InstanceBookDaoFactory {
    public  BookDao getBookDao(){
        return new BookDaoImpl();
    }
}

配置

<bean id="factoryBean" class="com.hhh.factory.InstanceBookDaoFactory"></bean>
        <bean id="bookDao" factory-bean="factoryBean" factory-method="getBookDao"></bean>

先配置实例化工厂类的bean对象,再通过factory-bean和factory-method来获取BookDaoImpl实现类的对象与id对应,相当于

InstanceBookDaoFactory instanceBookDaoFactory = new InstanceBookDaoFactory();
        BookDao bookDao1 = instanceBookDaoFactory.getBookDao();

但是这样相当的麻烦,还要先配置实例化工厂类的bean对象,所以我们可以让实例化工厂类实现FactoryBean接口,让程序知道不是获取这个实例化工厂类的bean对象,而是通过它里面的方法来获取指定的bean对象

public class InstanceBookDaoFactory implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new BookDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }
}
<bean id="bookDao" class="com.hhh.factory.InstanceBookDaoFactory"></bean>

因为InstanceBookDaoFactory实现了FactoryBean接口,所以不会获取InstanceBookDaoFactory的bean对象而是获取getObject()方法返回对象的bean对象

 依赖注入方式

 第一种setter注入

  • 简单类型
  • 引用类型(自定义类型)
public class BookServiceImpl implements BookService {
    BookDao bookDao;
    Integer num;
    @Override
    public void save() {
        System.out.println("bookService");
        System.out.println("num="+num);
        bookDao.save();
    }

    @Override
    public void setBookDao(BookDao bookDao) {
        this.bookDao=bookDao;
    }

    @Override
    public void setNum(Integer num) {
        this.num=num;
    }

}
<bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"></property>
        <property name="num" value="10"></property>
    </bean>

简单类型使用value属性进行赋值(依赖注入)

结果:

 

如果没有setXxx()方法,就会报错:Bean property 'num' is not writable or has an invalid setter method. 

第二种:构造器注入

  • 简单类型
  • 引用类型(自定义类型)
public class BookServiceImpl implements BookService {
    BookDao bookDao;
    Integer num;

    public BookServiceImpl(BookDao bookDao, Integer num) {
        this.bookDao = bookDao;
        this.num = num;
    }

    @Override
    public void save() {
        System.out.println("bookService");
        System.out.println("num="+num);
        bookDao.save();
    }
}

 

 <bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl">
       <constructor-arg name="bookDao" ref="bookDao"></constructor-arg>
        <constructor-arg name="num" value="20"></constructor-arg>
    </bean>

<constructor-arg>name属性是有参构造函数里面的参数名字

结果

或者也可以这样配置

<bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl">
       <constructor-arg type="com.hhh.dao.BookDao"  ref="bookDao"></constructor-arg>
        <constructor-arg index="1" value="20"></constructor-arg>
    </bean>

 type就是参数的类型,index就是有参构造函数里参数位置的索引

 依赖自动装配,<autowire>

public class BookServiceImpl implements BookService {
    BookDao bookDao;

    @Override
    public void save() {
        System.out.println("bookService");
        bookDao.save();
    }

    @Override
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}
 <bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.hhh.service.impl.BookServiceImpl" autowire="byType">
    </bean>

byType是容器通过类型匹配来查看自己是否有与BookServiceImpl类的成员变量相同类型bean对象,如果有就进行注入,没有就空指针异常

也可以使用byName,通过成员变量的名字来寻找,必须与id的名字一样 

集合注入

public class ResourceServiceImpl implements ResourceService {
    private String[] array;
    private List<String> list;
    private Set<String>set;
    private Map<String,String>map;
    private Properties properties;

    @Override
    public String toString() {
        return "ResourceServiceImpl{" +
                "array=" + Arrays.toString(array) +
                ", list=" + list +
                ", set=" + set +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }

    public void setArray(String[] array) {
        this.array = array;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

 配置

<bean id="resourceService" class="com.hhh.service.impl.ResourceServiceImpl">
        <property name="array">
            <array>
                <value>array1</value>
                <value>array2</value>
                <value>array3</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>
        <property name="set">
            <set>
<!--                set会去重-->
                <value>set1</value>
                <value>set1</value>
                <value>set3</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="mapKey1" value="value1"></entry>
                <entry key="mapKey2" value="value2"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="propKey1">value1</prop>
                <prop key="propKey2">value2</prop>
            </props>
        </property>
    </bean>
public class App {
    public static void main(String[] args) {
        //初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        ResourceService resourceService = (ResourceService) ctx.getBean("resourceService");
        System.out.println(resourceService);
    }
}

结果:

 Bean的生命周期

public class BookDaoImpl implements BookDao {
    public void init(){
        System.out.println("bookDao init");
    }
    @Override
    public void save() {
        System.out.println("bookDao save");
    }
    public void destroy(){
        System.out.println("bookDao destroy");
    }
}

配置

<bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl" init-method="init" destroy-method="destroy"></bean>
public class App {
    public static void main(String[] args) {
        //初始化容器
        ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("springContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();

        ctx.registerShutdownHook();//使用完自己关闭,写在哪都可以
        //暴力关闭
        //ctx.close();
    }
}

结果:

我们可以发现自己写init方法,和destroy方法还要再bean标签中自己配置,太过麻烦,我们可以实现spring提供的接口来重写方法

public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean {
   
    @Override
    public void save() {
        System.out.println("bookDao save");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("bean destroy");
    }

    @Override
//根据名字我们可以发现是先依赖注入再初始化bean对象
    public void afterPropertiesSet() throws Exception {
        System.out.println("bean init");
    }
}

根据方法名字我们可以发现是先依赖注入再初始化bean对象

这样一来我们就不用自己配置了

   <bean id="bookDao" class="com.hhh.dao.Impl.BookDaoImpl"></bean>

 

相关推荐

  1. 使用SpringContextHolder获取 Spring 容器Bean

    2024-07-18 05:24:01       43 阅读
  2. Spring容器加载BeanJVM加载类

    2024-07-18 05:24:01       21 阅读
  3. SpringBean标签配置IOC依赖注入详解

    2024-07-18 05:24:01       34 阅读
  4. Spring @Component @Bean 区别

    2024-07-18 05:24:01       30 阅读
  5. spring笔记一(bean/IoC)

    2024-07-18 05:24:01       32 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 05:24:01       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 05:24:01       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 05:24:01       58 阅读
  4. Python语言-面向对象

    2024-07-18 05:24:01       69 阅读

热门阅读

  1. 8个步骤彻底清理Docker镜像

    2024-07-18 05:24:01       28 阅读
  2. C#调用非托管dll,并从dll中再调用C#中的方法

    2024-07-18 05:24:01       23 阅读
  3. tomcat日志与log4j日志保留最近7天

    2024-07-18 05:24:01       23 阅读
  4. 一次超时导致的协程泄露

    2024-07-18 05:24:01       20 阅读
  5. day7 错误恢复(Panic Recover)

    2024-07-18 05:24:01       16 阅读
  6. c++邻接表

    2024-07-18 05:24:01       19 阅读
  7. Swift 数据类型

    2024-07-18 05:24:01       22 阅读
  8. 入门C语言只需一个星期(星期二)

    2024-07-18 05:24:01       22 阅读
  9. 国产大模型体验:DeepSeek、Kimi与智谱清言

    2024-07-18 05:24:01       20 阅读