Spring学习Day01

概述

  1. 什么是Spring:
    Spring是分层的JavaSE/EE引用full-stack(全站式)轻量级开源框架,以IoC(控制反转)、AOP(面面向切面编程)为内核。
  2. 发展历程:
    1997年,IBM提出了EJB的思想。
    1998年,SUN制定了规范标准EJB1.0
    2004年,Rod Johnson阐述了J2EE开发不使用EJB的解决方式(Spring雏形)
    2017年,发布spring5.0通用版
  3. Spring优势:
    方便解耦,简化开发、AOP支持、使命式事务的支持、方便程序的测试、集成各种优秀的框架、降低了JavaEE API的使用难度。
  4. 体系结构:来自B站截图

程序的耦合与解耦

耦合: 程序间(类、方法)的依赖关系
解耦:降低程序间的依赖关系,应该做到编译器不依赖,运行时才依赖。
解耦思路:使用反射来创建对象,避免使用new;通过读取配置文件来获取要创建对象的全限定类名。
分别创建:
持久层接口:

public interface AccountDao {

    /**
     * 模拟保存
     */
    void saveAccount();
}

持久层实现类:

public interface AccountDao {

    /**
     * 模拟保存
     */
    void saveAccount();
}

业务层接口:

public interface AccountService {

    /**
     * 模拟保存
     */
    void saveAccount();
}

业务层实现类:

public class AccountServiceImpl implements AccountService {
    AccountDao accountDao = new AccountDaoImpl();
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

模拟view层:

public class Client {
    public static void main(String[] args) {
        AccountService accountService = new AccountServiceImpl();
        accountService.saveAccount();
    }
}

这样使用会在视图层调用业务层;业务层调用持久层的方法。如果其中某个类出现缺失等问题,则会在程序编译时报错,耦合性太高了。所以下面使用工厂类来映射对象减少程序间的耦合行。
工厂类:

 /** 创建Bean对象的工厂
 * bean:在计算机英语中为可重用组件。
 *
 * JavaBean:用Java语言编写的可重用组件。
 *
 * 这个类用于创建Service和Dao对象
 * 1. 需要一个配置文件来配置service和dao
 *   配置内容:唯一表示=全限定类名(key=value)
 *   可以是xml也可以是properties
 * 2. 读取配置文件中的内容,反射创建对象
 */
public class BeanFactory {

//    定义一个Properties对象
    private static Properties properties;

//  定义一个Map容器用于存放要创建的对象
    private static Map<String ,Object> beans;

    static {
        try {
//          实例化对象
            properties = new Properties();
//          获取配置对象流(使用类加载器获取)
            InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
//          加载配置文件
            properties.load(inputStream);
//          实例化容器
            beans = new HashMap<String, Object>();
//          取出配置文件中所有的kay
            Enumeration<Object> keys = properties.keys();
//          遍历枚举
            while (keys.hasMoreElements()){
//                取出key
                String key = keys.nextElement().toString();
//                根据key获取value
                String beanPath = properties.getProperty(key);
//                创建反射对象
                Object value = Class.forName(beanPath).newInstance();
                beans.put(key,value);

            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new ExceptionInInitializerError("初始化配置文件失败");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据bean名称获取对象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName){
        return beans.get(beanName);
    }

}

bean.properties:

accountService=com.springDemo.service.Impl.AccountServiceImpl
accountDao=com.springDemo.dao.Impl.AccountDaoImpl

然后修改业务层实现类和模拟的试图层:

业务层实现类

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao = (AccountDao) BeanFactory.getBean("accountDao");
//    AccountDao accountDao = new AccountDaoImpl();
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

模拟试图层:

public class Client {
    public static void main(String[] args) {
        AccountService accountService = (AccountService) BeanFactory.getBean("accountService");
//        AccountService accountService = new AccountServiceImpl();
        accountService.saveAccount();
    }
}

以达到减少耦合的目的。

IoC(控制反转)

指app和资源之间没有必然的联系,使用工厂类去联系拥有独立的控制。把对象创建的权力交给框架。
用于削减耦合。
spring依赖:

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

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

    <!--把对象的创建交给spring来管理-->
    <bean id="accountService" class="com.springDemo.service.Impl.AccountServiceImpl"></bean>

    <bean id="accountDao" class="com.springDemo.dao.Impl.AccountDaoImpl"></bean>

</beans>

模拟试图:

public class Client {
    public static void main(String[] args) {
//       获取springIoC核心容器并且获取id对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
//        根据id获取bean对象 下面两种方法都可以
        AccountService accountService = (AccountService) applicationContext.getBean("accountService");
        AccountService accountService1 = applicationContext.getBean("accountService",AccountService.class);
        accountService.saveAccount();
    }
}

ApplicationContext下的三个常用实现类:

  1. ClassPathXmlApplicationContext:
    加载类路径下的配置文件,要求配置文件必须在类路径下。
  2. FileSystemXmlApplicationContext:
    加载磁盘任意路径下的配置文件(必须有访问权限)。
  3. AnnotatiionConfigApplicationContext:
    用于读取注解创建容器。

ApplicationContext与BeanFactory:

  1. ApplicationContext:
    在构建核心容器时,采用立即加载方式。只要一读完配置文件就创建配置的对象;单例对象适用。
  2. BeanFactory:
    延迟加载的方式。什么时候根据id获取对象了什么时候创建对象;多例对象使用。已经过时。

Spring创建Bean的三种方式:

  1. 使用默认构造函数:
    使用bean标签且没有除了id和class以外的其它属性。但是如果此类中没有默认构造函数则会创建失败
    <bean id="accountService" class="com.springDemo.service.Impl.AccountServiceImpl"></bean>
  1. 使用普通工厂中的方法创建对象
    使用某个类中的方法,并存入spring容器
   <bean id="BeanFactory" class="com.springDemo.factory.BeanFactory"></bean>
    <bean id="accountService" factory-bean="BeanFactory" factory-method="getAccountService"></bean>

方法:

    public AccountService getAccountService(){
        return new AccountServiceImpl();
    }
  1. 使用工厂类中的静态方法创建对象:
    使用某个类中的静态方法创建对象,并存入spring容器
<bean id="accountService" class="com.springDemo.factory.BeanFactory" factory-method="getStaticAccountService"></bean>
  public static AccountService getStaticAccountService(){
        return new AccountServiceImpl();
    }

Bean的作用范围:
scope属性:

  1. singletoon:单例的(默认值)
  2. prototype:多例的
  3. request:作用于web应用的请求范围
  4. session:作用于web应用的会话范围
  5. global-session:作用于集群环境的会话范围(全局会话范围),不是集群环境就是session

Bean对象的生命周期:

  1. 单例对象:
    当容器创建时产生对象,只要容器还在对象就一直存在,容器销毁对象消失。和容器一样
  2. 多例对象
    使用对象时创建,只要在运行过程中就一直存在,当对象长时间不用,且没有别的对象引用时,有Java的垃圾回收机制回收。

依赖注入(Dependency Injection)

依赖关系的维护就称之为依赖注入。

注入的数据类型:

经常改变的数据不使用注入。

  1. 基本类型和String
    ----------------------------往下看----------------------------
  2. 其它Bean
    ----------------------------往下看----------------------------
  3. 复杂类型/集合类型
    用于给List结构标签注入的有:
    list、array、set
    用于给Map结构标签注入的有:
    map props
    结构相同标签可以互换。
 <!--复杂类型的注入-->
    <bean id="accountService" class="com.springDemo.service.Impl.AccountServiceImpl">
        <!--注入数组-->
        <property name="myStrs">
            <array>
                <value>AAA</value>
                <value>AAA</value>
                <value>AAA</value>
            </array>
        </property>
        <!--注入list-->
        <property name="myList">
            <list>
                <value>BBB</value>
                <value>BBB</value>
                <value>BBB</value>
            </list>
        </property>
        <!--注入set-->
        <property name="mySet">
            <set>
                <value>BBB</value>
                <value>BBB</value>
                <value>BBB</value>
            </set>
        </property>
        <!--注入Map-->
        <property name="myMap">
            <map>
                <entry key="testA" value="aaa"></entry>
                <entry key="testB">
                    <value>BBB</value>
                </entry>
                <entry key="testA" value="aaa"></entry>
            </map>
        </property>
        <!--注入Props-->
        <property name="myProps">
            <props>
                <prop key="A">aa</prop>
                <prop key="A">aa</prop>
                <prop key="A">aa</prop>
            </props>
        </property>
    </bean>
注入的方式:
  1. 使用构造函数提供:
    bean标签内包含的constructor-arg标签:
    constructor标签内的属性:
    type:指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的数据类型。
    index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引从0开始。
    name:用于指定给构造函数中指定的参数赋值(常用)。
    value:用于提供基本类型和String类型的数据。
    ref:用于其它的Bean类型,就是指在spring的IoC核心容器中出现的Bean对象。
    优势:在获取Bean对象时,注入数据是必须的操作,否则对象是无法构建成功的。
    弊端:改变了Bean对象的实例化方式,使在创建对象时如果用不到数据也必须要提供值。
    demo:
   private String name;
    private Integer age;
    private Date birthday;

    public AccountServiceImpl(String name,Integer age,Date birthday){
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }
    <bean id="accountService" class="com.springDemo.service.Impl.AccountServiceImpl">
        <constructor-arg name="age" value="1"></constructor-arg>
        <constructor-arg name="name" value="Tom"></constructor-arg>
        <constructor-arg name="birthday" ref="now"></constructor-arg>
    </bean>
    <bean id="now" class="java.util.Date"></bean>
  1. 使用set方法提供 (更常用)
    property标签(bean内部):
    property标签内的属性:
    name:用于指定给构造函数中指定的set方法名称。
    value:用于提供基本类型和String类型的数据。
    ref:用于其它的Bean类型,就是指在spring的IoC核心容器中出现的Bean对象。
    优势:创建对象时没有明确的约束,可以直接使用构造函数。
    弊端:如果有某个成员必须有值,则set方法无法保证一定注入。
    demo:
 private String name;
    private Integer age;
    private Date birthday;

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

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    <!--set注入-->
    <bean id="accountService" class="com.springDemo.service.Impl.AccountServiceImpl">
        <property name="name" value="text"></property>
        <property name="birthday" ref="now"></property>
        <property name="age" value="1"></property>
    </bean>
    <bean id="now" class="java.util.Date"></bean>
  1. 使用注解提供:
    另一篇博客详细的写了注解的用法。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值