Spring工厂详解

Spring工厂详解

第一章 引言

1.1 EJB存在的问题

EJB(Enterprise Java Bean)主要存在两个问题:

  1. 运行环境苛刻;
  2. 代码移植性差。

总结:EJB是一个重量级的框架。

1.2 什么是Spring

Spring是一个轻量级的JavaEE解决方案,整合了众多优秀的设计模式。

  • 轻量级:

    1. 对于运行环境是没有额外要求的:
      • 开源 tomcat resion jetty
      • 收费 weblogic websphere
    2. 代码移植性高
      • 不需要实现额外的接口
  • JavaEE的解决方案:

    Spring对于JavaEE开发中的各层(Controller、Service、Dao)都有相应的解决方案。

  • 整合设计模式:

    1. 工厂设计模式
    2. 代理设计模式
    3. 模板设计模式
    4. 策略设计模式

1.3 设计模式

  • 广义概念:面向对象设计中,解决特定问题的经典代码;
  • 狭义概念:GOF4人帮定义的23种设计模式:工厂、适配器、装饰器、门面、代理、模板…

1.4 什么是工厂设计模式

  • 概念:通过工厂类,创建对象:

  • 好处:解耦合

    • 耦合:指的是代码之间的强关联关系,乙方的改变会影响到另一方。

    • 问题:不利于代码的维护。

    • 简单的理解为:把接口的实现类,硬编码再程序中:

      UserService userService = new UserServiceImpl();

1.5 简单的工厂设计模式

在applicationContext.properties中编写相关类名与类路径的对应关系:

userService = com.itheima.basic.UserServiceImpl
userDao = com.itheima.basic.UserDaoImpl

定义简单的工厂类:

public class BeanFactory {
   

    private static Properties env = new Properties();

    //使用静态代码块,在对象创建时初始化加载相关配置文件
    static{
   
        InputStream inputStream = null;
        try {
   
            inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
            env.load(inputStream);
        } catch (IOException e) {
   
            e.printStackTrace();
        }finally {
   
            if (inputStream != null){
   
                try {
   
                    inputStream.close();
                } catch (IOException e) {
   
                    e.printStackTrace();
                }
            }
        }
    }
    /*
        对象的创建方式:
        1.直接调用构造方法,创造对象:UserService userService = new UserServiceImpl();
        2.使用反射的方式,创建对象,解耦合:Class.forName("全限定类名");
     */

    public static Object getBean(String className){
   

        Object object = null;
        try {
   
            Class aClass = Class.forName(env.getProperty(className));
            object =  aClass.newInstance();
        } catch (InstantiationException e) {
   
            e.printStackTrace();
        } catch (IllegalAccessException e) {
   
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
   
            e.printStackTrace();
        }
        return object;

    }
}

测试类中利用BeanFactory工厂类获取对象:

    @Test
    public void test01(){
   
//        UserService userService = new UserServiceImpl();

        //使用工厂类创建对象,替代传统的new创建对象,解耦合
        UserService userService = (UserService) BeanFactory.getBean("userService");

        userService.login("name","suns");

        User user = new User("user","123456");

        userService.register(user);
    }

对于UserServiceImpl中的UserDao成员变量:

private UserDao userDao =(UserDao) BeanFactory.getBean("userDao");
  • 通用工厂的的使用方式:

    1. 定义类;

    2. 通过配置文件的配置告知工厂(applicationContext.properties)

      • key(类名)=value(全限定类名)
    3. 通过工厂获得类的对象

      • UserService userService = (UserService) BeanFactory.getBean("userService");
        

1.6 总结

Spring本质:工厂、ApplicationContext(ApplicationContext.xml)

第二章 第一个Spring程序

2.1 环境搭建

  • Spring的jar包:

        <dependencies>
            <!-- Spring的应用上下文依赖:
                    其中还依赖了:spring-aop、spring-beans、spring-core、spring-expression、spring-jcl     -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.9.RELEASE</version>
            </dependency>
        </dependencies>
    
  • Spring的配置文件:

    • Spring配置文件放置的位置:可以放在任意位置;
    • Spring配置文件的命名:可以任何名字,建议叫做:applicationContext.xml

2.2 Spring的核心API

  • ApplicationContext:

    作用:Spring提供的ApplicationContext这个工厂,用于对象的创建。

    好处:解耦合

  • ApplicationContext接口类型:

    接口:屏蔽实现的差异

    主要有两种实现:

    • 非WEB环境:ClassPathXmlApplicationContext
    • WEB环境:XmlWebApplicationContext
  • 重量级资源:

    ApplicationContext工厂的对象占用大量的内存,不会频繁的创建这个对象,一个应用只会创建一个工厂对象,所以ApplicationContext可以被并发访问,一定是线程安全的。

2.3 程序开发

  1. 创建类型
  2. 配置文件的配置ApplicationContext.xml
  3. 通过工厂类,获得对象:这里使用ApplicationContext的一个实现类:ClassPathXmlApplicationContext
  • 创建一个Person类;

  • 在ApplicationContext.xml配置该类型:

        <!--
        id属性:名字,唯一;
        class属性:配置全限定类名
    
        -->
        <bean id="person" class="com.itheima.basic.Person"/>
    
  • 在测试类中,使用ClassPathXmlApplicationContext类加载配置文件,并通过该类的类对象创建配置文件中配置的类的对象:

        /**
         *用于测试Spring的第一个程序
         */
        @Test
        public void test02(){
         
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            Person person = context.getBean("person", Person.class);
            System.out.println(person);//com.itheima.basic.Person@9a7504c
    
        }
    

2.4 细节分析

  • 名词解释:

    Spring工厂创建的对象,叫做bean或者组件(component)

  • Spring工厂的相关方法:

    • getBean方法的三种重载方式:
      1. getBean(“person”):创建id=“person”的对象,此方法创建的是Object’对象,需要强转为响应类型的对象;
      2. getBean(“person”,Person.class):创建创建id=“person”的Person类型的对象;
      3. getBean(Person.class):创建类型为Person的对象,此方法要求配置文件中类型为Person的bean标签只能有一个。
    • getBeanDefinitionNames:获得所有bean标签的id属性值(或name属性值)
    • getBeanNamesForType:获得某种类型的bean的id属性值
    • containsBean:判断是否有指定id值的bean
    • containsBeanDefinition:判断是否有指定id值的bean
  • Spring配置文件的细节:

    1. 只配置class属性,而不配置id属性,这时候Spring会为这个bean提供一个id值,如: com.itheima.basic.Person#0。
      • 应用场景:如果这个bean只需要使用一次,那么就可以省略id值。
    2. name属性:
      • 作用:用于在Spring的配置文件中,为bean对象定义别名。
      • 与id属性的不同之处:别名可以定义多个,多个别名间以逗号相隔。

2.5 Spring工厂的底层实现原理(简易版)

  1. 通过ClassPathXmlApplicationContext工厂读取配置文件applicationContext.xml

  2. 获取bean标签的相关信息,如:

    • id的值=person
    • class的值=com.itheima.spring.domain.Person
  3. 通过反射创建对象,如:

    Class clazz = Class.forName("com.itheima.spring.domain.Person");
    Person person = (Person)clazz.newInstance();
    
  4. 反射创建对象,其实底层还是构造方法创建对象:

    Person person = new Person();
    

细节:

  • 如果这个类的构造方法是私有的,那么Spring也会调用这个类的构造方法创建对象,这是因为反射可以调用私有方法.

思考:

  • 问题:未来在开发过程中,是不是所有的对象,都会交给Spring工厂来创建对象呢?
  • 答案:理论上来说是的,但是有特例:实体对象(entity)是不会交给Spring来创建的,它是由持久层框架来创建的.

第三章 Spring与日志框架的整合

Spring与日志框架进行整合,日志框架就可以在控制台中,输出Spring框架运行过程中的一些重要的信息.

好处:便于了解Spring框架的运行过程,利于程序的调试.

  • Spring如何整合日志框架:
    • Spring 1\2\3 早期都是与commons-logging.jar
    • Spring5.x默认整合的日志框架logback\log4j

3.1 Spring5.x整合log4j

  1. 引入log4j的jar包
  2. 引入log4j.properties配置文件
  • pom:

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.7</version>
    </dependency>
    
  • log4j.properties:

    # resources文件根目录下
    ### 配置根 ###
    log4j.rootLogger=debug, console
    
    ### 日志输出到控制台显示 ###
    log4j.appender.console=org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target=System.out
    log4j.appender.console.layout=org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
    

第四章 注入(Injection)

4.1 什么是注入

通过Spring的工厂及配置文件,为所创建的对象的成员变量赋值.

  • 为什么需要注入:通过编码的方式,为成员变量进行赋值,存在耦合:

    ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
    Person person1 = context.getBean("person1",Person.class);
    //通过代码为成员变量赋值,存在耦合
    person1.setId(1);
    person1.setName("小王");
    System.out.println(person1);
    
  • 如何进行注入:

    1. 类为成员变量提供get\set方法;

    2. 配置Spring的配置文件:

          <bean id="person1" class="com.itheima.basic.Person">
              <property name="id" >
                  <value>1</value>
              </property>
              <property name="name">
                  <value>suns</value>
              </property>
          </bean>
      

4.2 Spring注入的原理分析(简易版)

  • Spring通过底层调用对象属性对应的set方法,完成成员变量的赋值,这种方法成为Set注入:
<bean id="person1" class="com.itheima.basic.Person">
    等效于
    Person person1 = new Person()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值