初识Spring与Spring-IOC容器

一、Spring框架的概念

  1. Spring是一款企业级级开发的开源框架
  2. Spring提供IOC容器和AOP框架:
    • IOC解决了对象的创建以及对象管理,同时解决对象与对象之间的依赖
    • AOP解决的是一些公共业务逻辑(事物管理、日志收集等)
  3. Spring是一个“粘合剂”
    • 采用Spring去集成第三方框架或者组件(MyBatis/Redis/RabbitMQ/Hibernate…),集成原理还是基于IOC容器

二、Spring框架组件

在这里插入图片描述

  • 数据访问相关组件(Data Access):
    • Spring JDBC/Spring ORM/Spring OXM
  • Web应用相关组件(Web):
    • Spring Web、Spring MVC(重点)、Spring Websocket…
  • AOP(面向切面编程)、Aspects(切面)
  • 核心容器组件(Core Container):
    • Beans(Bean相关内容:BeanFactory)
    • Context(Spring配置的上下文 ApplicationContext)
    • Core
    • SpEL(Spring的EL表达式)
  • 测试组件(Spring-test):
    • mock(模拟)测试、Random Port(随机端口测试)、TestContext Framework(测试上下文框架)

三、集成Spring框架

  • 方法:在项目的pom中添加spring-context依赖,通过Maven的依赖传递将Spring其他核心组件的jar包也一起依赖进项目(aop/beans/core/spel),Spring开源的源代码存放在GitHub上

  • 代码:

    <!--依赖Spring相关jar包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>
    

四、BeanFactory和ApplicationContext

在这里插入图片描述

​ ApplicationContext是BeanFactory的子类,它除了拥有BeanFactory的功能外,还包含有国际化、资源加载、事件传递等等

五、Bean实例化的模拟

思路

  1. 读取xml,解析xml配置(dom4j解析)
  2. 获取<bean id="" class="" />标签,将bean标签的属性封装到对象中
  3. 将解析后的<bean>标签的对象存入集合中
  4. 遍历解析后的Bean标签(id, class)集合,同时利用反射机制创建对象,并将id和对象存入map中
  5. 编写一个getBean(id)的方法获取bean实例化后的对象

代码实现

  1. 编写一个BeanFactory,暴露一个getBean接口

    /**
     * 模拟Bean工程提供获取Bean的方法
     */
    public interface BeanFactory {
        public Object getBean(String id);
    }
    
  2. 编写BeanFactory的实现类MyClassPathXmlApplicationContext()

    /**
     * 模拟的是一个ApplicationContext上下文容器
     */
    public class MyClassPathXmlApplicationContext implements BeanFactory {
        private Map<String, Object> beans = new HashMap<>();// 实例化后的对象放入map
        private List<MyBean> myBeans;// 存放已读取bean 配置信息
    }
    
  3. 编写一个构造器,传入xml配置文件,调用解析方法进行xml读取、解析,调用实例化对象的方法去实例化对象(应用反射机制)

    // 构造器,传入xml配置文件名
    public MyClassPathXmlApplicationContext(String fileName) {
        this.readBeansXml(fileName);// 读取并解析配置文件
        this.insranceBeans(); // 实例化bean
    }
    
  4. 读取、解析xml配置文件,将bean标签内容存入集合的MyBean对象中(bean metadata)

    /**
     * 读取 并解析xml 配置文件
     * @param fileName
     */
    private void readBeansXml(String fileName) {
        URL url=this.getClass().getClassLoader().getResource(fileName);
        // 判断xml配置文件是否存在
        if (url == null) {
            System.out.println("资源文件未找到!");
            return;
        }
        // 解析xml配置文件
        SAXReader saxReader=new SAXReader();// 创建saxReader 对象
        Document doc= null;
        try {
            doc = saxReader.read(url);
        } catch (DocumentException e) {
            e.printStackTrace(); // 打印异常的堆栈信息
            return;
        }
        Map<String, String> map = new HashMap<>(); // 一定要加泛型
        map.put("my", "http://www.springframework.org/schema/beans");  //将xml命名空间放入map
        XPath xPath= doc.createXPath("//my:bean");//定义查找路径
        xPath.setNamespaceURIs(map);
        List<Element> elements = xPath.selectNodes(doc);
        if (CollectionUtils.isEmpty(elements)) {
            return;
        }
        myBeans = new ArrayList<>();
        for(Element element : elements){
            //System.out.println(element.attributeValue("id")+element.attributeValue("class"));
            MyBean myBean = new MyBean(element.attributeValue("id"), element.attributeValue("class"));
            myBeans.add(mytBean);
        }
    }
    
  5. 遍历bean的元数据信息(MyBean集合)信息,利用反射实例化对象,同时存储到map中

    /**
     * 实例化bean 对象
     */
    private void insranceBeans() {
        // 先判断<bean>标签集合是否有值
        if (CollectionUtils.isEmpty(myBeans)) {
            return;
        }
        // 遍历<bean>标签,同时利用反射机制生成对象,并将对象存入map中,其中key为bean对象的id,value是对象
        for(MyBean myBean: myBeans){
            try {
                beans.put(myBean.getId(), Class.forName(myBean.getClazz()).newInstance());
            } catch (Exception e) {
                continue;
            }
        }
    }
    
  6. 重写getBean方法,从map中返回bean的实例化后的对象

    /**
     * 根据id 名获取bean
     */
    @Override
    public Object getBean(String id) {
        return beans.get(id);
    }
    

六、IOC容器加载多个配置文件

  • 第一种:启动ApplicationContext上下文容器时,允许加载多个配置文件

  • 第二种:用某一个公共的配置文件,把其他配置文件通过<import resource="" />导入进来

    <bean id="helloService" class="com.myspring.service.HelloService" />
    <import resource="controller.xml" />
    <import resource="service.xml" />
    <import resource="dao.xml" />
    
    public class AppTest {
    
        @Test
        public void testMultiXml() {
            // 启动IOC容器(加载配置文件生成ApplicationContext)
            ApplicationContext ac = new ClassPathXmlApplicationContext("controller.xml", "dao.xml", "service.xml");
            // 获取Bean对象
            UserController userController = ac.getBean("userController", UserController.class);
            UserService userService = ac.getBean("userService", UserService.class);
            UserDao userDao = ac.getBean("userDao", UserDao.class);
            // 调用Bean方法
            userController.show();
            userService.add();
            userDao.save();
        }
    
        @Test
        public void testSingleXml() {
            // 启动IOC容器(加载配置文件生成ApplicationContext)
            ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
            // 获取Bean对象
            UserController userController = ac.getBean("userController", UserController.class);
            UserService userService = ac.getBean("userService", UserService.class);
            UserDao userDao = ac.getBean("userDao", UserDao.class);
            // 调用Bean方法
            userController.show();
            userService.add();
            userDao.save();
        }
    }
    

七、Bean的实例化方式

1. 构造器实例化

  • 通过默认构造器创建 空构造方法必须存在 否则创建失败(简单|重要)
<bean id="userServiceImpl" class="com.myspring.service.impl.UserServiceImpl" ></bean>

2. 静态工厂实例化

  • 编写一个工厂类,同时编写一个静态方法,该方法返回需要创建的对象
/**
 * 静态工厂实例化Bean
 */
public class StaticFactory {
   /**
    * 编写一个静态方法,同时返回一个实例化对象
    * @return
    */
    public static UserService createUserService(){
      return new UserService();
   } 
}
<?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,配置的class指向工厂类,添加factory-method属性指向创建对象的静态方法-->
    <bean id="userService" class="com.myspring.factory.StaticFactory" factory-method="createUserService" />
    
</beans>

3. 实例化工厂方法

  • 编写一个工厂类,同时编写一个非静态方法,该方法返回需要创建的对象,在配置时,需要先实例化工厂bean
/**
 * 实例化工厂创建Bean对象
 */
public class InstanceFactory {
    /**
     * 此方法不需要静态化
     * @return
     */
    public UserService createUserService() {
        return new UserService();
    }
}
<?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="instanceFactory" class="com.myspring.factory.InstanceFactory"  /> <!--工厂bean-->

    <!--实例化UserService Bean-->
    <bean id="userService" factory-bean="instanceFactory" factory-method="createUserService" />
    
</beans>

八、对象依赖与注入

IOC本质问题 ***

  • IOC:控制反转,就是由原来主动创建对象改成交给Spring创建对象

    // 主动创建
    public class UserController {
    	private UserService userService = new UserService();
    }
    
    // 交由第三方创建再传入
    public class UserController {
    	private UserService userService ;
    	public UserController(UserService userService) {
    		this.userService = userService;
    	}
    }
    

依赖注入(DI) ***

  • 依赖:对象与对象之间的关系,注入由第三方(Spring)在实例化对象时进行注入。
    • 因此DI是IOC的另外一种表达方式,换个说法:IOC是DI的理论基础
  • 注入:可以简单理解为赋值

依赖注入的方式 ***

1. 构造器注入 **

​ 通过构造器传参,将对象注入给对应的属性

  • 注入对象

    • 例子:

      // 编写一个NoteDao,里面有个findNote()方法
      public class NoteDao {
          public void find() {
              System.out.println("查询笔记。。。");
          }
      }
      
      // 编写一个NoteService,包含NoteDao属性,编写一个构造器,把NoteDao注入进来
      public class NoteService {
          private NoteDao noteDao;
          public NoteService() {}
          // 创建一个构造器方法
          public NoteService(NoteDao noteDao) {
              System.out.println("构造器注入。。。");
              this.noteDao = noteDao;
          }
          /**
           * 查找笔记
           */
          public void findNote() {
              noteDao.find();
          }
      }
      
      <!--实例化NoteDao对象-->
      <bean id="noteDao" class="com.myspring.dao.NoteDao"/>
      
      <!--实例化NoteService-->
      <bean id="noteService" class="com.myspring.service.NoteService">
          <!--给NoteService(NoteDao noteDao)构造器注入NoteDao的对象-->
          <constructor-arg name="noteDao" ref="noteDao"/>
      </bean>
      
      /**
       * 测试
       */
      public class NoteServiceTest {
          private ApplicationContext ac;
      
          @Before
          public void initAc() {
              // 启动IOC容器
              ac = new ClassPathXmlApplicationContext("application-note.xml");
          }
      
          @Test
          public void testFindNote() {
              // 获取UserService对象
              NoteService noteService = ac.getBean("noteService", NoteService.class);
              noteService.findNote();
          }
      }
      
      
  • 注入基本类型

    public class Note {
        private Integer id;
        private String content;
        private Integer userId;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public Integer getUserId() {
            return userId;
        }
    
        public void setUserId(Integer userId) {
            this.userId = userId;
        }
    
        public Note() {
        }
    
        public Note(Integer id, String content, Integer userId) {
            this.id = id;
            this.content = content;
            this.userId = userId;
        }
    }
    
    <!--实例化Note对象-->
    <bean id="note" class="com.myspring.model.Note">
        <!--其中name为参数名,value参数值,index为参数下标-->
        <constructor-arg name="id" value="1" index="0" />
        <constructor-arg name="userId" value="123" index="2"/>
        <constructor-arg name="content" value="今天是个好天气" index="1"/>
    </bean>
    
  • 简化配置:通过引入c标签,简化配置构造器注入

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:c="http://www.springframework.org/schema/c"
           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">
    
        <!--实例化NoteDao对象-->
        <bean id="noteDao" class="com.myspring.dao.NoteDao"/>
    
        <!--实例化NoteService-->
        <bean id="noteService" class="com.myspring.service.NoteService" c:noteDao-ref="noteDao" />
            <!--给NoteService(NoteDao noteDao)构造器注入NoteDao的对象
            <constructor-arg name="noteDao" ref="noteDao"/>
        </bean>-->
    
        <!--实例化Note对象-->
        <bean id="note" class="com.myspring.model.Note" c:id="1" c:userId="123"
              c:content="今天是个好天气" />
            <!--其中name为参数名,value参数值,index为参数下标
            <constructor-arg name="id" value="1" index="0" />
            <constructor-arg name="userId" value="123" index="2"/>
            <constructor-arg name="content" value="今天是个好天气" index="1"/>
        </bean>-->
    
    </beans>
    
2. setter注入 ***

​ 就是编写一个属性的set方法,然后进行依赖注入

  • 注入对象

    public class UserDao {
    
        public void save() {
            System.out.println("Save User...");
        }
    
    }
    
    public class UserService {
    
        private UserDao userDao;
    
        /**
         * 编写一个添加用户的方法
         */
        public void addUser() {
            userDao.save();
        }
    
        /**
         * UserDao的set方法
         * @param userDao
         */
        public void setUserDao(UserDao userDao) {
            System.out.println("setter注入UserDao对象");
            this.userDao = userDao;
        }
    }
    
    <?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唯一标记这个bean,class属性代表是这个bean的类-->
        <bean id="userService" class="com.myspring.service.UserService" >
            <!--依赖注入UserDao对象-->
            <property name="userDao" ref="userDao" />
        </bean>
    
        <!--实例化UserDao对象-->
        <bean id="userDao" class="com.myspring.dao.UserDao" />
    
    </beans>
    
    @Test
    public void testAddUser() {
        // 启动IOC容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
        // 获取UserService对象
        UserService userService = ac.getBean("userService", UserService.class);
        // 调用addUser()方法
        userService.addUser();
    }
    
  • 注入基本类型

    package com.myspring.model;
    
    public class User {
        private Integer id;
        private String userName;
        private String password;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
    }
    
    <!--实例化User对象-->
    <bean id="user" class="com.myspring.model.User">
        <!--基本类型注入-->
        <property name="id" value="2" />
        <property name="userName" value="banzhang"/>
        <property name="password" value="1234555"/>
    </bean>
    
    @Test
    public void testAddUser2() {
        // 启动IOC容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
        // 获取UserService对象
        UserService userService = ac.getBean("userService", UserService.class);
        // 调用addUser()方法
        User user = ac.getBean("user", User.class);
        userService.addUser(user);
    }
    
  • 简化set注入配置:通过引入p标签简化

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:p="http://www.springframework.org/schema/p"
                   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唯一标记这个bean,class属性代表是这个bean的类-->
        <bean id="userService" class="com.myspring.service.UserService" p:userDao-ref="userDao" />
            <!--依赖注入UserDao对象
            <property name="userDao" ref="userDao" />
        </bean>-->
    
        <!--实例化UserDao对象-->
        <bean id="userDao" class="com.myspring.dao.UserDao" />
    
        <!--实例化User对象-->
        <bean id="user" class="com.myspring.model.User" p:id="2"
              p:password="122345" p:userName="banzhang" />
            <!--基本类型注入
            <property name="id" value="2" />
            <property name="userName" value="banzhang"/>
            <property name="password" value="1234555"/>
        </bean>-->
    
    </beans>
    
3. 静态工厂注入(不常用)
4. 实例化工厂注入(不常用)

九、List、Set、Map、Properties、空字符、null注入

看代码:

public class User {
    private Integer id;
    private String userName;
    private String password;

    private List<String> noddles;
    private Set<String> cookies;
    private Map<String, String> views;
    private Properties games;


    public Integer getId() {
        return id;
    }

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

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

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

    public List<String> getNoddles() {
        return noddles;
    }

    public void setNoddles(List<String> noddles) {
        this.noddles = noddles;
    }

    public Set<String> getCookies() {
        return cookies;
    }

    public void setCookies(Set<String> cookies) {
        this.cookies = cookies;
    }

    public Map<String, String> getViews() {
        return views;
    }

    public void setViews(Map<String, String> views) {
        this.views = views;
    }

    public Properties getGames() {
        return games;
    }

    public void setGames(Properties games) {
        this.games = games;
    }
}
<bean id="user" class="com.myspring.model.User">
    <property name="id" value="0" />
    <property name="userName" value=""/> <!--空字符串-->
    <property name="password"> <!--null值-->
        <null />
    </property>
    <property name="noddles">
        <list>
            <value>河南烩面</value>
            <value>臊子面</value>
            <value>担担面</value>
            <value>兰州拉面</value>
        </list>
    </property>

    <property name="cookies">
        <set>
            <value>曲奇</value>
            <value>奥利奥</value>
            <value>闲趣</value>
        </set>
    </property>

    <property name="views">
        <map>
            <entry>
                <key><value>上海</value></key>
                <value>城隍庙</value>
            </entry>
            <entry>
                <key><value>北京</value></key>
                <value>四合院</value>
            </entry>
            <entry>
                <key><value>西安</value></key>
                <value>大雁塔</value>
            </entry>
        </map>
    </property>

    <property name="games">
        <props>
            <prop key="暴雪">暗黑破坏神</prop>
            <prop key="育碧">刺客信条</prop>
            <prop key="任天堂">马里奥制造</prop>
        </props>
    </property>

</bean>

十、自动装配(装载)

概念

  • 利用注解方式自动装配bean的依赖关系,达到简化依赖注入的操作
  • 使用时必须要开启注解驱动<context:annotation-config />

1. @Autowired

  • 它是Spring框架注解

  • 根据类型查询bean(byType)

  • 默认情况下依赖的bean必须要存在,否则会提示找不到该bean异常

    • 因为required属性控制了依赖的bean是否必须存在,默认是@Autowired(required=true)
  • @Autowired既可以设置在属性上,也可以设置在setter方法上

    public class UserController {
    
        @Autowired // 推荐,其中required属性代表bean是否必须存在,默认为true
        private UserService userService;
    
        public void show(User user) {
            System.out.println("调用控制层方法。。");
            userService.addUser(user);
        }
    
        // @Autowired // 不推荐
        // public void setUserService(UserService userService) {
        // 		this.userService = userService;
        // }
    }
    
    <!--开启自动装载注入-->
    <context:annotation-config />
    
    <bean name="userController" class="com.myspring.controller.UserController" />
    

2. @Resource

  • 它是Jdk的注解
  • 如果没有指定name(@Resource),先根据name(byName)查询,查询不到再根据类型(byType)匹配,比如
@Resource
private UserService userService;
  • 如果指定name属性,那么只会根据name进行查询(byName)
@Resource(name = "userService")
private UserService userService;

3. @Qualifier

  • @Resource(name=“userService”) = @Autowired + @Qualifier(“userService”)

十一、Spring IOC 扫描器——扫描 + 注解实例化Bean

1. 添加扫描配置

  • 在配置文件中添加:<context:component-scan base-package=" "/>进行扫描配置,其中base-package代表扫描的包路径

  • 不需要开启注解驱动<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"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
        <!--扫描注解,其中base-package属性代表扫描的package-->
        <context:component-scan base-package="com.myspring"/>
    </beans>
    

2. 注解标记实例类

  • @Component注解,如果不能区分这个类是属于那一层,那么当做一个普通组件交给Spring管理
  • @Controller注解,标记这个类是控制层
  • @Service注解,标记这个类是业务逻辑层
  • @Repository注解,标记这个类是数据访问逻辑层

十二、Spring配置Bean的方式

第一种:声明式配置

  • 通过在xml中配置bean标签进行实例化
  • 包括构 造器实例化、静态工厂和实例化工厂实例化

第二种:Spring IOC 扫描器

  • 扫描 + 注解,通过component-scan进行扫描包 + 组件(@Component)注解

第三种:通过注解方式配置Bean

  • @Configuration(类注解) + @Bean(方法)

  • 首先要也要有扫描@Configuration注解的类

  • 通过@Configuration标记的类相当于<beans ></beans>

  • @Bean相当于<bean id=“默认是方法名称” class=“返回类型” />

  • 举例:

    • 第一步:编写HelloController和HelloService类

      @Controller // 标记这个controller交给Spring管理
      public class UserController {
      
          @Autowired
          private UserService userService;
      
          public void show(User user) {
              System.out.println("调用控制层方法。。");
              userService.addUser(user);
          }
      }
      
      public class HelloService {
          public void say() {
              System.out.println("Hello Java Config....");
          }
      }
      
    • 第二步:配置一个HelloService的Bean

      @Configuration
      public class HelloServiceConfiguration {
      
          @Bean// 默认使用方法名作为bean的名称
          public HelloService helloService() {
              return new HelloService();
          }
      }
      
    • 第三步:添加扫描

      <?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:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
                      http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
      
          <!--扫描注解,其中base-package属性代表扫描的package-->
          <context:component-scan base-package="com.myspring"/>
      </beans>
      

十三、Spring Bean 的作用域

作用域分类名称说明
单例singleton在SpringIOC容器中,Bean创建好之后会存在
单例Bean的缓存池中,获取Bean时从池中直接
拿取即可,性能高
原型prototype不会缓存,每次获取每次创建
Web应用request、session、application、webSocket必须要有 web 环境支持,并配置相应的容器
监听器或拦截器从而能应用这些作用域
  • 默认是单例 singleton

    • 即在SpringIOC容器中,Bean创建好之后会存在单例Bean的缓存池中,获取Bean时从池中直接拿取即可,性能高

      在这里插入图片描述

    • 注意:lazy-init 是懒加载,如果等于 true 时作用是指 Spring 容器启动的时候不会去实例化这个 bean,而是在程序调用时才去实例化。默认是 false 即 Spring 容器启动时实例化

    • 容器在启动的情况下就实例化所有 singleton 的 bean 对象 的好处:

      • 提前发现潜在的配置问题
      • Bean 对象存在于缓存中,使用时不用再去实例化 bean,加快程序运行效率
    • 一般来说对于无状态或状态不可改变的 对象适合使用单例模式

  • 原型 prototype,不会缓存,每次获取每次创建

    • 通过 scope=“prototype” 设置 bean 的类型 ,每次向 Spring 容器请求获取Bean 都返回一个全新的 Bean,相对于 “singleton” 来说就是不缓存 Bean,每次都是一个根据 Bean 定义创建的全新 Bean

      在这里插入图片描述

  • Web应用中存在作用域:request、session、application、webSocket

十四、Bean 的生命周期

(1)定义

  • 声明式配置
  • 扫描器 + 注解
  • 编程式(java config)@Configuration + @Bean

(2)初始化

  • 启动容器,生成上下文对象ApplicationContext

    • (FileSystemXmlApplicationContex、ClassPathXmlApplicationContex、AnnotationConfigApplicationContext)
  • 可以再通过 init-method 添加初始化代码

(3)使用

  • 调用BeanFactory中的getBean方法获取Bean,再调用Bean的方法

(4)销毁

  • 可以通过 destroy-method 添加销毁代码
  • 可以通过调用AbstractApplicationContext的close()方法进行销毁

Bean初始化的时序图

在这里插入图片描述

package com.myspring.model;

import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;

public class User implements InitializingBean, BeanNameAware {

   private String userId;
   private String userName;
   private String email;
   private String hometown;
   private String job;
   private String beanName;
   
   public User() {
      System.out.println("**************第一步: 调用Bean的默认构造方法**************");
      this.userId = "bean1: myspring001";
      System.out.println("bean1的值: " + this);
   }
   
   @Override
   public void afterPropertiesSet() throws Exception {
      System.out.println("bean2的值: " + this);
      System.out.println("**************第三步: 检查Bean是否实现了InitializingBean接口**************");
      this.userName = "bean3: 隔壁老王";
      this.email = "bean3: www@qqq.com";
      System.out.println("bean3的值: " + this);
   }
   
   public void init() {
      System.out.println("**************第四步: 检查配置文件中是否指定了init-method方法**************");
      this.hometown = "bean3: 上海";
      System.out.println("bean4: " + this);
   }
   
   public void destroy () {
      System.out.println("**************服务停止**************");
   }
   
   public String getUserId() {
      return userId;
   }
   public void setUserId(String userId) {
      this.userId = userId;
   }
   public String getUserName() {
      return userName;
   }
   public void setUserName(String userName) {
      this.userName = userName;
      System.out.println("**************第二步: Bean的配置文件中是否注入了bean的属性值**************");
      System.out.println("bean11的值: " + this);
   }
   public String getEmail() {
      return email;
   }
   public void setEmail(String email) {
      this.email = email;
   }
   public String getHometown() {
      return hometown;
   }
   public void setHometown(String hometown) {
      this.hometown = hometown;
   }
   public String getBeanName() {
      return beanName;
   }

   @Override
   public void setBeanName(String beanName) {
      System.out.println("**********设置bean的名称**********");  
      this.beanName = "userBeanName";
   }
   public String getJob() {
      return job;
   }
   public void setJob(String job) {
      this.job = job;
   }
   @Override
   public String toString() {
      return "User [userId=" + userId + ", userName=" + userName + ", email="
            + email + ", hometown=" + hometown + ", job=" + job
            + ", beanName=" + beanName + "]";
   }
}
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--声明式配置
    <bean id="userService" class="com.myspring.service.UserService" destroy-method="destroy" init-method="initUserService"  />
-->
    <bean id="user" class="com.myspring.model.User" init-method="init" destroy-method="destroy">
        <property name="userName" value="abcd" />
    </bean>

</beans>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值