Spring IoC容器与Bean管理

Spring 初识

IoC控制反转

  • IoC控制反转,全称Inverse of Control,是一种设计理念
  • 由代理人创建与管理对象,消费者通过代理人来获得对象
  • IoC的目的是降低程序与程序之间直接耦合

解决什么问题?

对象直接饮用导致对象硬性关联,程序难以扩展。比如:顾客想要吃各种各样的苹果,就需要顾客取世界各地购买苹果,非常麻烦。

Spring IoC容器与Bean管理

加入Ioc容器将对象统一管理,让对象关联变为弱耦合。就像上面的场景:如果出现了摊贩,那么顾客就不用跑到各地去买水果了,而是由摊贩购买好之后,顾客根据自己的需求购买响应的苹果。

Spring IoC容器与Bean管理

 DI依赖注入

  • IoC是设计理念,是现代程序设计遵循的标准,是宏伟目标
  • DI(Dependency Injection) 是具体技术实现,是微观实现
  • DI在Java中利用反射技术是心啊对象注入(Injection)

Spring

Spring IoC容器与Bean管理

含义 

  • Spring可以从狭义与广义两个角度看
  • 狭义角度的Spring是指Spring框架(Spring Fremework)
  • 广义角度Spring是指Spring生态体系

狭义的Spring框架

  • Spring框架是企业开发复杂性的恶一站式解决方案
  • SPring框架的核心是IoC容器与AOP面向切面编程
  • Spring IoC负责创建与管理系统对象,并在此基础上扩展功能

广义Spring生态体系

Spring IoC容器与Bean管理

Spring IoC容器

IoC容器是Spring生态的地基,用于统一创建与管理对象依赖

Spring IoC容器与Bean管理

 如上:Spring IoC容器将A的依赖B对象注入进来,使用者只需要从中提取就可以了。

Spring IoC容器职责

  • 对象的控制权交由第三方统一管理(IoC控制反转)
  • 利用Java反射技术实现运行时对象创建与关联(DI依赖注入)
  • 基于配置提高应用程序的可维护性与扩展性

Spring IoC初体验

eg: 比如三个孩子 Lily、Andy、Luna分别喜欢吃甜的、酸的、软的苹果。盘子里有三个苹果:红富士、青苹果、金帅。

那孩子们如何获得喜欢的苹果呢?

Apple.class

package com.imooc.spring.ioc.entity;

public class Apple {
    private String title;
    private String color;
    private String origin;

    public Apple() {
        //System.out.println("Apple对象已经创建, " + this);
    }

    public Apple(String title, String color, String origin) {
        this.title = title;
        this.color = color;
        this.origin = origin;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getOrigin() {
        return origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
    }
}

Child.class

package com.imooc.spring.ioc.entity;

public class Child {
    private String name;
    private Apple apple;

    public Child() {

    }

    public Child(String name, Apple apple) {
        this.name = name;
        this.apple = apple;
    }

    public String getName() {
        return name;
    }

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

    public Apple getApple() {
        return apple;
    }

    public void setApple(Apple apple) {
        this.apple = apple;
    }

    public void eat() {
        System.out.println(name + "吃到了" + apple.getOrigin() + "种植的" + apple.getTitle());
    }
}

传统方式

Application.class

public class Application {
    public static void main(String[] args) {
        Apple apple1 = new Apple("红富士", "红色", "欧洲");
        Apple apple2 = new Apple("青苹果", "绿色", "中亚");
        Apple apple3 = new Apple("金帅", "黄色", "中国");

        Child lily = new Child("莉莉", apple1);
        Child andy = new Child("安迪", apple2);
        Child luna = new Child("露娜", apple3);

        lily.eat();
        andy.eat();
        luna.eat();

    }
}

输出结果:

Spring IoC容器与Bean管理

但是这样会有一个弊端,如果后面需要更改喜欢的苹果的时候,我们就需要在源代码这里修改。在开发过程中,往往源代码涉及到的内容较多,修改复杂且容易影响其他地方,很容易出错。

使用IoC容器方式:

在resources目录下创建applicationontext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 在IoC容器启动时,自动由Spring实例化Apple对象,取名sweetApple放入到容器中 -->
    <bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="红富士"></property>
        <property name="origin" value="欧洲"></property>
        <property name="color" value="红色"></property>
    </bean>

    <bean id="sourApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="青苹果"></property>
        <property name="origin" value="中亚"></property>
        <property name="color" value="绿色"></property>
    </bean>

    <bean id="softApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="金帅"></property>
        <property name="origin" value="中国"></property>
        <property name="color" value="黄色"></property>
    </bean>

    <bean id="rdApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="蛇果"></property>
        <property name="origin" value="美国"></property>
        <property name="color" value="红色"></property>
    </bean>

    <bean id="lily" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="莉莉"/>
        <property name="apple" ref="softApple"/>
    </bean>

    <bean id="andy" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="安迪"/>
        <property name="apple" ref="rdApple"/>
    </bean>

    <bean id="luna" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="露娜"/>
        <property name="apple" ref="sweetApple"/>
    </bean>
</beans>

SpringApplication.class

public class SpringApplication {
    public static void main(String[] args) {
        //创建Spring IoC容器,并根据配置文件在容器中实例化对象
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        Apple sweetApple = context.getBean("sweetApple", Apple.class);
        System.out.println(sweetApple.getTitle());
        //从IoC容器中提取beanId=lily的对象
        Child lily = context.getBean("lily", Child.class);
        lily.eat();
        Child andy = context.getBean("andy", Child.class);
        andy.eat();
        Child luna = context.getBean("luna", Child.class);
        luna.eat();

    }
}

执行结果:

Spring IoC容器与Bean管理

这样做的好处是,我们涉及到修改时,只需要修改applicationContent.xml中的内容即可.

 使用XML方式实现Spring IoC

 上面说的applicationContext.xml就是使用xml文件方式实现Spring IoC的一种。

实现方式:

  1. 基于构造方法对对象实例化
  2. 基于动态工厂实例化
  3. 基于工厂实例方法实例化

Spring框架组成模块

Spring IoC容器与Bean管理

 ApplicationContext实现类

  • ClassPathXmlApplicationContext
  • AnnotationConfigApplicationContext
  • WebApplicationContext

基于构造方法对对象实例化

默认构造方法

在 applicationContext.xml文件:

<!--bean标签默认通过默认构造方法创建对象-->
    <bean id="apple1" class="com.imooc.spring.ioc.entity.Apple">

Apple.class 中修改为:

public Apple() {
        System.out.println("Apple对象已创建," + this);
    }

打印输出:

Spring IoC容器与Bean管理

带参构造方法

applicationContext.xml

<!--使用带参构造方法实例化对象-->
    <bean name="apple2" class="com.imooc.spring.ioc.entity.Apple">
        <constructor-arg name="title" value="红富士"/>
        <constructor-arg name="color" value="红色"/>
        <constructor-arg name="origin" value="欧洲"/>
        <constructor-arg name="price" value="19.8"/>
    </bean>

    <bean id="apple3" class="com.imooc.spring.ioc.entity.Apple">
        <constructor-arg index="0" value="红富士"/>
        <constructor-arg index="1" value="欧洲"/>
        <constructor-arg index="2" value="红色"/>
        <constructor-arg index="3" value="19.8"/>
    </bean>

 Apple.class

public Apple(String title, String origin, String color, Float price) {
        System.out.println("通过带参构造方法创建对象, " + this);
        this.title = title;
        this.color = color;
        this.origin = origin;
        this.price = price;
    }

打印输出:

Spring IoC容器与Bean管理

基于工厂实例化对象

静态工厂

/**
 * 静态工厂通过静态方法创建对象,隐藏创建对象的细节
 */
public class AppleStaticFactory {
    public static Apple createSweetApple(){
        //logger.info("")
        Apple apple = new Apple();
        apple.setTitle("红富士");
        apple.setOrigin("欧洲");
        apple.setColor("红色");
        return apple;
    }
}

在applicationContext.xml中

<!--利用静态工厂获取对象-->
    <bean id="apple4" class="com.imooc.spring.ioc.factory.AppleStaticFactory"
          factory-method="createSweetApple"/>

测试:

 Apple apple4 = context.getBean("apple4", Apple.class);
        System.out.println(apple4.getTitle());

 输出:

Spring IoC容器与Bean管理

工厂实例

/**
 * 工厂实例方法创建对象是指IoC容器对工厂类进行实例化并调用对应的实例方法创建对象的过程
 */
public class AppleFactoryInstance {
    public Apple createSweetApple(){
        Apple apple = new Apple();
        apple.setTitle("红富士");
        apple.setOrigin("欧洲");
        apple.setColor("红色");
        return apple;
    }
}

在applicationContext.xml中

 <!--利用工厂实例方法获取对象-->
    <bean id="factoryInstance" class="com.imooc.spring.ioc.factory.AppleFactoryInstance"/>
    <bean id="apple5" factory-bean="factoryInstance" factory-method="createSweetApple"/>

然后测试输出即可.

从IoC容器中提取 Bean

方式一:
Apple apple = context.getBean("apple", Apple.class);

方式二:
Apple apple = (Apple)context.getBean("apple");

推荐使用方式一

id和name属性相同点

  • bean id 与 name 都是设置对象在IoC容器中唯一标识
  • 两者在同一个配置文件中都不允许出现重复
  • 两者允许在多个配置文件中出现重复,新对象覆盖旧对象

id和name属性不同点

  • id要求更为严格,一次只能定义一个对象标识(推荐)
  • name更为宽松,一次允许定义多个对象标识
  • tips:id与name的命名要求有意义,按驼峰命名书写
<bean name="apple2,apple7" class="com.imooc.spring.ioc.entity.Apple">
        <constructor-arg name="title" value="红富士2号"/>
        <constructor-arg name="color" value="红色"/>
        <constructor-arg name="origin" value="欧洲"/>
        <constructor-arg name="price" value="29.8"/>
    </bean>
    <!-- 没有id与name的bean默认使用类名全称作为bean标识 -->
    <bean class="com.imooc.spring.ioc.entity.Apple">
        <constructor-arg name="title" value="红富士3号"/>
        <constructor-arg name="color" value="红色"/>
        <constructor-arg name="origin" value="欧洲"/>
        <constructor-arg name="price" value="29.8"/>
    </bean>

路径匹配表达式

 ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");

Spring IoC容器与Bean管理

 加载多个配置文件:

String[] configLocations = new String[]{"classpath:applicationContext.xml","classpath:applicationContext-1.xml"};
        //初始化IoC容器并实例化对象
       ApplicationContext context = new ClassPathXmlApplicationContext(configLocations);

路径表达式

Spring IoC容器与Bean管理

 对象依赖注入

依赖注入是指运行时将容器内对象利用反射赋给其他对象的操作

Spring IoC容器与Bean管理

  •  基于setter方法注入对象
  • 基于构造方法注入对象

基于setter方法注入对象

<property name="" value=""/> : 静态属性

<property name=""ref=""/> : 动态属性

<bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
        <!-- IoC容器自动利用反射机制运行时调用setXXX方法为属性赋值 -->
        <property name="title" value="红富士"/>
        <property name="color" value="红色"/>
        <property name="origin" value="欧洲"/>
        <property name="price" value="19.8"/>
    </bean>

    <bean id="lily" class="com.imooc.spring.ioc.entity.Child">
        <property name="name" value="莉莉"/>
        <!-- 利用ref注入依赖对象 -->
        <property name="apple" ref="sweetApple"/>
    </bean>

依赖注入的优势

举例:

applicationContext-dao.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="bookDao" class="com.imooc.spring.ioc.bookshop.dao.BookDaoOracleImpl">

    </bean>
</beans>

applicationContext-serice.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="bookService" class="com.imooc.spring.ioc.bookshop.service.BookService">
        <!--id=bookDao-->
        <property name="bookDao" ref="bookDao"/>
    </bean>
</beans>

BookDao

public interface BookDao {
    public void insert();
}

BookDaoImpl

public class BookDaoImpl implements BookDao {
    public void insert() {
        System.out.println("向MySQL Book表插入一条数据");
    }
}

BookService

public class BookService {
    private BookDao bookDao ;
    public void purchase(){
        System.out.println("正在执行图书采购业务方法");
        bookDao.insert();
    }

    public BookDao getBookDao() {
        return bookDao;
    }

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

BookShopApplication

public class BookShopApplication {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext-*.xml");
        BookService bookService = context.getBean("bookService", BookService.class);
        bookService.purchase();
    }
}

输出:

Spring IoC容器与Bean管理

优点: 比如数据库由MySQL迁移到Oracle.这时候只需要将BookDao这个Bean的class更改为Oracle即可.

注入集合对象

 注入List

Spring IoC容器与Bean管理

注入set

 Spring IoC容器与Bean管理

注入map 

Spring IoC容器与Bean管理

注入Properties 

Spring IoC容器与Bean管理

 Properties中的key和value只能是String类型

查看容器内对象 

//获取容器内所有beanId数组
        String[] beanNames = context.getBeanDefinitionNames();

for (String beanName:beanNames){
            System.out.println(beanName);
            System.out.println("类型:" + context.getBean(beanName).getClass().getName());
            System.out.println("内容:" + context.getBean(beanName));
        }
 Computer computer = context.getBean("com.imooc.spring.ioc.entity.Computer", Computer.class);

当有多个相同类的Bean时:

 <bean class="com.imooc.spring.ioc.entity.Computer">
        <constructor-arg name="brand" value="微星"/>
        <constructor-arg name="type" value="台式机"/>
        <constructor-arg name="sn" value="8389280012"/>
        <constructor-arg name="price" value="3000"/>
    </bean>

    <bean class="com.imooc.spring.ioc.entity.Computer">
        <constructor-arg name="brand" value="华硕"/>
        <constructor-arg name="type" value="笔记本"/>
        <constructor-arg name="sn" value="9089380012"/>
        <constructor-arg name="price" value="6000"/>
    </bean>
Computer computer1 = context.getBean("com.imooc.spring.ioc.entity.Computer#0", Computer.class);
Computer computer1 = context.getBean("com.imooc.spring.ioc.entity.Computer#1", Computer.class);

Bean对像的作用域及生命周期

bean scope属性

  • bean scope属性用于决定对象何时被创建与作用范围
  • bean scope配置将影响容器内对象的数量
  • 默认情况下bean会在IoC容器创建后自动实例化,全局唯一

scope用法

Spring IoC容器与Bean管理

bean scope属性清单

Spring IoC容器与Bean管理

 singleton的线程安全问题

Spring IoC容器与Bean管理

 

singleton在容器是单例多线程执行,存在线程安全风险 

在单线程下:

Spring IoC容器与Bean管理

当在多线程中:在A用户操作了a.setNum(1)之后,在另一个线程,B用户操了a.setNum(2) .这个时候,A用户打印a.num 就会出现 2,和A用户设置值不同.

Spring IoC容器与Bean管理

prototype多例 

Spring IoC容器与Bean管理

prototype在容器中多实例,占用更多资源,不存在线程安全问题 

singleton和prototype对比

Spring IoC容器与Bean管理

bean生命周期

 Spring IoC容器与Bean管理

细节调整

  •  prototype使对象创建与init_method延迟至执行业务
  • prototype使对象不再受IoC容器管理,不再触发destroy-method
  • 延迟加载lazy-init属性可让对象创建与初始化延迟到执行代码阶段

生命周期在实战中的应用

singleton和prototype的初始化

singleton的初始化:

applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.imooc.spring.ioc.dao.UserDao"/>

    
</beans>

在SpringApplication中添加:

public class SpringApplication {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
     
    }
}

打印输出:

Spring IoC容器与Bean管理

也就是说在IoC容器初始化的时候,为我们创建了bean. 

prototype初始化:

 applicationContext.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDao" class="com.imooc.spring.ioc.dao.UserDao" scope="prototype"/>

    
</beans>

然后在SpringApplication中测试:

public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        System.out.println("======IoC容器已初始化=======");
       UserDao userDao1 = context.getBean("userDao", UserDao.class);
}

输出为:

Spring IoC容器与Bean管理

也就是说,在IoC容器创建的时候,并没有为我们初始化bean对像,而是在我们获取对象的时候,才初始化.singleton模式的初始化顺序跟书写顺序一致。

下面会初始化两个bean对象.

<bean id="userDao" class="com.imooc.spring.ioc.dao.UserDao" scope="prototype"/>

    <bean id="userService" class="com.imooc.spring.ioc.service.UserService">
        <property name="userDao" ref="userDao"/>
    </bean>

在多数情况下,Dao层,server层,control层都是单例的。

实现极简IoC容器

目录结构:

Spring IoC容器与Bean管理

 Apple类

package com.imooc.spring.ioc.entity;

public class Apple {
    private String title;
    private String color;
    private String origin;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getOrigin() {
        return origin;
    }

    public void setOrigin(String origin) {
        this.origin = origin;
    }
}

 然后在applicationContext.xml中添加bean的信息:

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="sweetApple" class="com.imooc.spring.ioc.entity.Apple">
        <property name="title" value="红富士"/>
        <property name="color" value="红色"/>
        <property name="origin" value="欧洲"/>
    </bean>
</beans>

自定义记载配置文件的方法:

接口:ApplicationContext

package com.imooc.spring.ioc.context;

public interface ApplicationContext {
    public Object getBean(String beanId);
}

实现类ClassPathXmlApplicationContext 

public class ClassPathXmlApplicationContext implements ApplicationContext {
    private Map iocContainer = new HashMap();

    /**
     * 读取配置文件
     */
    public ClassPathXmlApplicationContext() {
        try {
            String filePath = this.getClass().getResource("/applicationContext.xml").getPath();
            // 进行URL解码
            filePath = new URLDecoder().decode(filePath, "UTF-8");

            /**
             * 引入 dom4j和jaxen
             * Dom4j是Java的XML解析组件
             * Jaxen是Xpath表达式解释器
             */
            SAXReader reader = new SAXReader();
            Document document = reader.read(new File(filePath));
            // 读取 "bean" 标签
            List<Node> beans = document.getRootElement().selectNodes("bean");

            for (Node node : beans) {
                Element ele = (Element) node;

                String id = ele.attributeValue("id");
                String className = ele.attributeValue("class");

                Class c = Class.forName(className);
                Object obj = c.newInstance();

                List<Node> properties = ele.selectNodes("property");
                for (Node p : properties) {
                    Element property = (Element) p;
                    String propName = property.attributeValue("name");
                    String propValue = property.attributeValue("value");

                    // set方法
                    String setMethodName = "set" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
                    System.out.println("准备执行" + setMethodName + "方法注入数据");
                    Method setMethod = c.getMethod(setMethodName, String.class);
                    setMethod.invoke(obj, propValue);//通过setter方法注入数据
                }
                iocContainer.put(id, obj);
            }
            System.out.println(iocContainer);
            System.out.println("IOC容器初始化完毕");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getBean(String beanId) {
        return iocContainer.get(beanId);
    }
}

然后进行测试:

public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext();
        Apple apple = (Apple)context.getBean("sweetApple");
        System.out.println(apple);
    }
}

执行结果:

Spring IoC容器与Bean管理 

 

使用注解方式实现Spring IoC

基于注解的优势

  • 摆脱繁琐的XML形式的bean与依赖注入配置
  • 基于“声明式”的原则,更适合轻量级的现代企业应用
  • 让代码可读性变得更好,研发人员拥有更好的开发体验

三类注解:

  1. 组件类型注解 - 声明当前类的功能与职能
  2. 自动装配注解 - 根据属性特种自动注入对象
  3. 元数据注解 - 更细化的辅助IoC容器管理对象的注解

四种组件类型注解

  1. @Compponent  : 组件注解,通用注解,被该注解描述的类将被IoC容器管理并实例化
  2. @Controller  : 语义注解,说明当前类是MVC应用中的控制器类
  3. @Service. : 语义注解,说明当前类是Service业务服务类
  4. @Repository. : 语义注解,说明当前类是用于业务持久层,通常描述对应Dao类

Spring IoC容器与Bean管理  

两类自动装配注解

  1. 按类型装配
    1. @Autowired : 按容器内对象类型动态注入属性,由Spring机构提供
    2. @Inject : 基于JSR-330(Dependency Injection for Java)标准,其他同@Autowired,但不支持required属性
  2. 按名称装配
    1. @Named : 与@Inject配合使用,JSR-330规范,按属性名自动装配属性
    2. @Resource :基于JSR-330规范,优先按名称、再按类型智能匹配

元数据注解

Spring IoC容器与Bean管理

@Value 的读取属性文件

@Value("com.imooc")
private String config;

就是相当于在初始化的时候,config的值为"com.inooc",主要用户加载配置文件中的数据: @Value("${config}")

使用Java Config方式实现Spring IoC

基于Java Config的优势

  • 完全摆脱XML的束缚,使用独立Java类管理对象与依赖
  • 注解配置相对分散,利用Java Config可对配置集中管理
  • 可以在编译时进行依赖检查,不容易出错

Java Config核心注解

Spring IoC容器与Bean管理

Java Config初始化方式

 Spring IoC容器与Bean管理

 举例:

package com.imooc.spring.ioc;

import com.imooc.spring.ioc.controller.UserController;
import com.imooc.spring.ioc.dao.EmployeeDao;
import com.imooc.spring.ioc.dao.UserDao;
import com.imooc.spring.ioc.service.UserService;
import org.springframework.context.annotation.*;

@Configuration //当前类是一个配置类,用于替代applicationContext.xml
@ComponentScan(basePackages = "com.imooc")
public class Config {
    @Bean //Java Config利用方法创建对象,将方法返回对象放入容器,beanId=方法名
    public UserDao userDao(){
        UserDao userDao = new UserDao();
        System.out.println("已创建" + userDao);
        return userDao;
    }

    @Bean //Java Config利用方法创建对象,将方法返回对象放入容器,beanId=方法名
    @Primary
    public UserDao userDao1(){
        UserDao userDao = new UserDao();
        System.out.println("已创建" + userDao);
        return userDao;
    }

    @Bean
    //先按name尝试注入,name不存在则按类型注入
    public UserService userService(UserDao udao , EmployeeDao employeeDao){
        UserService userService = new UserService();
        System.out.println("已创建" + userService);
        userService.setUserDao(udao);
        System.out.println("调用setUserDao:" + udao);
        userService.setEmployeeDao(employeeDao);
        return userService;
    }

    @Bean //<bean id="xxx" clas="xxx">
    @Scope("prototype")
    public UserController userController(UserService userService){
        UserController userController = new UserController();
        System.out.println("已创建" + userController);
        userController.setUserService(userService);
        System.out.println("调用setUserService:" + userService);
        return userController;
    }
}

测试:

public class SpringApplication {
    public static void main(String[] args) {
        //基于Java Config配置IoC容器的初始化
        ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        System.out.println("=========================");
        String[] ids = context.getBeanDefinitionNames();
        for(String id : ids){
            System.out.println(id + ":" + context.getBean(id));
        }
    }
}

Spring IoC容器与Bean管理

 

上一篇:Spring介绍


下一篇:PHP 依赖注入,依赖反转 (IOC-DI)