04_01_Spring||day01_Spring第一天||day01_Spring第一天(总结篇)

Spring学习 共四天

  • 第一天:Spring框架的概述以及Spring中基于XML的IOC配置
  • 第二天:Spring中基于注解的IOC和IOC的案例
  • 第三天:Spring中的AOP和基于XML以及注解的AOP配置
  • 第四天:Spring中的JdbcTemplate以及Spring事务控制
  • 细说第一天学习内容:
    1. Spring的概述
      • Spring是什么
      • Spring的两大核心
      • Spring的发展历程和优势
      • Spring的体系结构
    2. 程序的耦合及解耦
      • 曾经案例中的问题
      • 工厂模式解耦
    3. IOC概念和Spring中的IOC
      • Spring中基于XML的IOC环境搭建
    4. 依赖注入(Dependency Injection)
    5. 作业:

1. Spring框架的概述

1.1 Spring是什么
  • Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:
    反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核
1.2 Spring发展历程
  • Rod Johnson(spring 之父)
  • 2017 年 9 月份发布了 spring 的最新版本 spring 5.0 通用版(GA)
1.3 Spring的优势
  1. 方便解耦,简化开发
    • 通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造
      成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可
      以更专注于上层的应用。
  2. AOP 编程的支持
    • 通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。
  3. 声明式事务的支持(配置的方式)
    • 可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,
  4. 提高开发效率和质量。
    • 方便程序的测试
      可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可
      做的事情。
  5. 方便集成各种优秀框架
    • Spring 可以降低各种框架的使用难度,提供了对各种优秀框架( Struts、 Hibernate、 Hessian、 Quartz
      等)的直接支持。
  6. 降低 JavaEE API 的使用难度
    • Spring 对 JavaEE API(如 JDBC、 JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的
      使用难度大为降低。
  7. Java 源码是经典学习范例
    • Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以
      及对 Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。
1.4 Spring的体系结构

2. IoC 的概念和作用

2.1 什么是程序的耦合
    * 程序的耦合
    *  耦合:程序间的依赖关系
    *      包括:
    *          类之间的依赖
    *          方法间的依赖
    *  解耦:
    *      降低程序间的依赖关系
    *  实际开发中:
    *      应该做到:编译期不依赖,运行期才依赖。
    *  解耦的思路:
    *      第一步:使用反射来创建对象,而避免使用new关键字。
    *      第二步:通过读取配置文件来获取要创建的对象权限定类名
  • 以JDBC做案例:
        public static void main(String[] args) throws Exception{
            ///JDBC的操作
            //1.注册驱动
            //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            Class.forName("com.mysql.jdbc.Driver");
            //2. 获取连接
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sy", "root", "1234");
            //3. 获取操作数据库的预处理对象
            PreparedStatement pstm = conn.prepareStatement("SELECT * FROM account");
            //4. 执行SQL, 得到结果集
            ResultSet rs = pstm.executeQuery();
            //5. 遍历结果集
            while (rs.next()){
                System.out.println(rs.getString("name"));
            }
            //6. 释放资源
            rs.close();
            pstm.close();
            conn.close();
        }
    
  1. 划分模块的一个准则:高内聚低耦合
  2. 耦合分类:(主要的几个)
    1. 内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另
      一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
    2. 公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大
      量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
    3. 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进
      行适当的动作,这种耦合被称为控制耦合。
    4. 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形
      式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另
      一些模块的输入数据。
  3. 总结
    • 耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须
      存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。
  4. 内聚和耦合
    • 内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。 ++内聚++是从
      功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事
      它描述的是模块内的功能联系。++耦合++是软件
      结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通
      过接口的数据
      程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之
      间的相互依存度却要不那么紧密。
    • 内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他
      模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。
2.2 分析工厂模式中的问题并改造(13)

  • 多例情况:将创建和获取对象写在getBean方法中
    • 类对象在创建时,重新初始化它的类中的属性和方法。
  • 单例情况:将创建对象写到BeanFactory方法中
    • 实现类中最好不要有局部的私有变量。(定义为成员变量即可改为单例的)
  • 代码演示:BeanFactory.java
    • 全限定类名
      • 就是类名全称,带包路径的用点隔开(创建对象必备的部分)
    • JavaBean:用Java语言编写的可重用组件。(比实体类范围大)
      • JavaBean > 实体类(可重用组件的一部分,比如业务层,持久层)
        /**
         * Created by GXWIsSuperMen on 2020/5/21.
         *  1. 创建一个Bean对象的工厂
         *
         *      * bean:在计算机英语中,有可重用的含义
         *
         *      * JavaBean:用Java语言编写的可重用组件。
         *          * JavaBean > 实体类(可重用组件的一部分,比如业务层,持久层)
         *
         *  2. Bean工厂目的:
         *      * 它就是我们创建Service和dao对象的
         *
         *  3. 如何创建:
         *      1.  需要一个配置文件来配置我们的Service和dao
         *          * 配置的内容:唯一标识=全限定类名(key=value)
         *              * 全限定类名:就是类名全称,带包路径的用点隔开(创建对象必备的部分)
         *      2.  通过读取配置文件中的配置内容,反射创建对象。
         *
         *  4. 配置文件可以是XML也可以是properties的(这里用properties)
         */
        public class BeanFactory {
            //定义一个Properties对象
            private static Properties props;
        
            //定义一个Map,用于存放我们要创建的对象。我们把它称为容器。
            private static Map<String, Object> beans;
        
            //使用静态代码块为Properties对象赋值
            static {
        
                try {
                    //实例化对象
                    props = new Properties();
                    //获取properties文件的流对象(用类加载器来获取)
                    InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
                    props.load(in);
        
                    //实例化容器
                    beans = new HashMap<String, Object>();
                    //取出配置文件中所有的key
                    Enumeration<Object> keys = props.keys();
                    //遍历枚举
                    while (keys.hasMoreElements()){
                        //取出每个key
                        String key = keys.nextElement().toString();
                        //根据key获取value
                        String beanPath = props.getProperty(key);
                        //反射创建对象(newInstance():每次都会调用默认构造函数创建对象)
                        Object value = Class.forName(beanPath).newInstance();
                        //把key和value存入到容器中
                        beans.put(key, value);
                    }
                } catch (Exception e) {
                    throw new ExceptionInInitializerError("初始化properties失败");
                }
        
            }
        
            /**
             * 根据Bean的名称获取bean对象
             * 单例:对象只有一个实例
             * @param beanName
             * @return
             */
            public static Object getBean(String beanName){
                return beans.get(beanName); //得到的就是对应的value
            }
        }
    
2.3 工厂模式解耦
  • 读取配置文件, 创建和获取三层对象的类就是工厂
2.4 控制反转-Inversion Of Control

  1. 被动接收的方式获取对象的思想就是控制反转,它是 spring 框架的核心之一。
    • 把创建的对象的权利交给框架(工厂)【控制反转的定义】
      • 包括:依赖注入和依赖查找
  2. IOC的作用
    • ++削减++计算机程序的耦合(解除我们代码中的依赖关系)。
    • IOC只能解决程序间的依赖关系,其他什么都干不了【总结】
  3. 自定义工厂类的内容交给了Spring所以我们来学Spring中的IOC

3. 使用 spring 的 IOC 解决程序耦合

  • Spring开发包目录介绍
  1. pring包中schema/aop是里面的一些约束
  2. Spring包中libs下的jar包一共就21个(每3个为一组,想看文档导入javadoc,想看源码sources
  3. pring包中docs(三个,前两个是api)
    • 第三个(spring-framework-reference)中index.html以后可能会经常翻阅【注】
3.1 Spring 基于 XML 的 IOC 细节
  1. BeanFactory 和 ApplicationContext【实际开发中】 的区别
    • ApplicationContext 单例对象适用
    • BeanFactory 多例对象适用
        BeanFactory 才是 Spring 容器中的顶层接口。
        ApplicationContext 是它的子接口。
        BeanFactory 和 ApplicationContext 的区别:
        创建对象的时间点不一样。
        ApplicationContext:只要一读取配置文件,默认情况下就会创建对象。
        BeanFactory:什么时候使用什么时候创建对象。
    
  2. ApplicationContext 接口的实现类
        ClassPathXmlApplicationContext:
        它是从类的根路径下加载配置文件 ==推荐使用这种==
        FileSystemXmlApplicationContext:
        它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
        AnnotationConfigApplicationContext:
        当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。
    
    • 使用案例:(表现层调业务层)
        //1. 获取核心容器对象
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2. 根据id获取bean对象
        Object as = ac.getBean("accountService");
        as.saveAccount();
        
        ===========================
        
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
            <constructor-arg name="name" value="泰斯特"></constructor-arg>
            <constructor-arg name="age" value="18"></constructor-arg>
            <constructor-arg name="birthday" ref="now"></constructor-arg>
        </bean>
    
        <!-- 配置一个日期对象 -->
        <bean id="now" class="java.util.Date"></bean>
    
3.2 IOC 中 bean 标签和管理对象细节
  • bean标签,spring的IOC容器掌握情况【*】
    <bean id="now" class="java.util.Date"></bean>
    * class的含义
        * 读取全限定类名,反射创建一个对象,并且存入到Spring的核心容器中。
    * id的含义
        * 通过id来讲后面的对象取出来
  1. bean标签
        作用:
            用于配置对象让 spring 来创建的。
            默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。
        属性:
            id: 给对象在容器中提供一个唯一标识。用于获取对象。
            class: 指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
            scope: 指定对象的作用范围。
                * singleton :默认值,单例的.
                * prototype :多例的.
                * request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
                * session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
                * global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session.
            init-method: 指定类中的初始化方法名称。
            destroy-method: 指定类中销毁方法名称。
    
  2. 实例化 Bean 的三种方式
    • 这里只写了常用的一个,剩下2个去详文看。
        第一种方式:使用默认无参构造函数
        <!--在默认情况下:
        它会根据默认无参构造函数来创建类对象。==如果 bean 中没有默认无参构造函数,将会创建失败。==
        -->
        
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>
    
  3. Bean的作用范围(默认情况是单例的
    • bean标签的scope属性
      • 作用:
        • 用于指定bean的作用范围
      • 取值:
        • singleton :默认值,单例的.
        • prototype :多例的.
        • request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
        • session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
        • global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session.
    • 注:global session的含义
  4. Bean对象的生命周期
    1. 单例对象(单例对象的生命周期和容器相同)
      • 出生:当容器创建时对象出生
      • 活着:只要容器在,对象一直活着
      • 死亡:容器销毁,对象消亡
    2. 多例对象
      • 出生:当我们使用对象时,spring框架为我们创建
      • 活着:对象只要在使用过程中,就一直活着
      • 死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
3.3 spring 的依赖注入
  1. 依赖注入的概念:
        依赖注入: Dependency Injection。 它是 spring 框架核心 ioc 的具体实现。
        我们的程序在编写时, 通过控制反转, 把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。
        ioc 解耦只是降低他们的依赖关系,但不会消除。 例如:我们的业务层仍会调用持久层的方法。
        那这种业务层和持久层的依赖关系, 在使用 spring 之后, 就让 spring 来维护了。
        简单的说,==就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。==
    
  2. 简述:
    • 依赖注入:
      • Dependency Injection
    • IOC的作用
      • 降低程序间的耦合(依赖关系)
    • 依赖关系的管理:
      • 以后都交给Spring来维护,在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明
    • 依赖关系的维护:
      • 就称之为依赖注入
    • 依赖注入
      • 能注入的数据:有三类
        1. 基本类型和String
        2. 其他bean类型(在配置文件中或者注解配置过的bean)
        3. 复杂类型/集合类
      • 注入的方式:有三种
        1. 使用构造函数提供
        2. 使用set方法提供
        3. 使用注解提供
  3. 构造函数注入【一般不用】
    • 涉及的标签:
      • constructor-arg
    • 属性:
      • name【常用赋值】:指定参数在构造函数中的名称 用这个找给谁赋值
      • value:它能赋的值是基本数据类型和 String 类型
      • ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
    • 注:xml中写入的都是字符串(spring会帮我们转换)
    • 构造函数注入的优势:
      • 在创建bean对象时,注入数据是必须的操作,负责对象无法创建成功。
    • 构造函数注入的劣势:
      • 改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
        顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置
        的方式,让 spring 框架来为我们注入。具体代码如下:
        /**
        */
        public class AccountServiceImpl implements IAccountService {
            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;
            }
            @Override
            public void saveAccount() {
                System.out.println(name+","+age+","+birthday);
            }
        }
        ===================================
        
        <!-- 使用构造函数的方式,给 service 中的属性传值
        要求:
        类中需要提供一个对应参数列表的构造函数。
        涉及的标签:
            constructor-arg
        属性:
            index:指定参数在构造函数参数列表的索引位置
            type:指定参数在构造函数中的数据类型(该数据类型也是构造函数中某个或某些参数的类型)
            name:指定参数在构造函数中的名称 用这个找给谁赋值
            =======上面三个都是找给谁赋值,下面两个指的是赋什么值的==============
            value:它能赋的值是基本数据类型和 String 类型
            ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
        -->
        ==================================
        
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
            <constructor-arg name="name" value="张三"></constructor-arg>
            <constructor-arg name="age" value="18"></constructor-arg>
            <constructor-arg name="birthday" ref="now"></constructor-arg>
        </bean>
        <bean id="now" class="java.util.Date"></bean>
    
  4. set 方法注入【开发中常用
    • 优势:
      • 创建对象时没有明确的限制,可以直接使用默认构造函数
    • 劣势:
      • 如果有某个成员必须有值,则获取对象是有可能set方法没有执行
        顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下:
        /** */
        public class AccountServiceImpl implements IAccountService {
            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;
            }
            @Override
            public void saveAccount() {
                System.out.println(name+","+age+","+birthday);
            }
        }
        ===============================
        
        <!-- 通过配置文件给 bean 中的属性传值:使用 set 方法的方式
        涉及的标签:
            property
        属性:
            name:找的是类中 set 方法后面的部分
            ref:给属性赋值是其他 bean 类型的
            value:给属性赋值是基本数据类型和 string 类型的
            实际开发中,此种方式用的较多。
        -->
        ===============================
        
        <bean id="accountService"             class="com.itheima.service.impl.AccountServiceImpl">
            <property name="name" value="test"></property>
            <property name="age" value="21"></property>
            <property name="birthday" ref="now"></property>
        </bean>
        <bean id="now" class="java.util.Date"></bean>
    
  5. 使用 p 名称空间注入数据(本质还是调用 set 方法)
    • 想了解去看详页
  6. 注入集合属性
    • 用于给List结构集合注入的标签:
      • array,list,set
    • 用于给Map结构集合注入的标签:
      • map, props
    • 结构相同,标签可以互换
        顾名思义,就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。
        我们这里介绍注入数组,List,Set,Map,Properties。具体代码如下:
        /***/
        public class AccountServiceImpl implements IAccountService {
            private String[] myStrs;
            private List<String> myList;
            private Set<String> mySet;
            private Map<String,String> myMap;
            private Properties myProps;
            public void setMyStrs(String[] myStrs) {
                this.myStrs = myStrs;
            }
            public void setMyList(List<String> myList) {
                this.myList = myList;
            }
            public void setMySet(Set<String> mySet) {
                this.mySet = mySet;
            }
            public void setMyMap(Map<String, String> myMap) {
                this.myMap = myMap;
            }
            public void setMyProps(Properties myProps) {
                this.myProps = myProps;
            }
            
            @Override
            public void saveAccount() {
                System.out.println(Arrays.toString(myStrs));
                System.out.println(myList);
                System.out.println(mySet);
                System.out.println(myMap);
                System.out.println(myProps);
            }
        }
        =============================
        
        <!-- 注入集合数据
        List 结构的:
            array,list,set
        Map 结构的
            (map,entry),(props,prop)
        -->
        =============================
        
        <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
            <!-- 在注入集合数据时,只要结构相同,标签可以互换 -->
            <!-- 给数组注入数据 -->
            <property name="myStrs">
                <set>
                    <value>AAA</value>
                    <value>BBB</value>
                    <value>CCC</value>
                </set>
            </property>
            <!-- 注入 list 集合数据 -->
            <property name="myList">
                <array>
                    <value>AAA</value>
                    <value>BBB</value>
                    <value>CCC</value>
                </array>
            </property>
            <!-- 注入 set 集合数据 -->
            <property name="mySet">
                <list>
                    <value>AAA</value>
                    <value>BBB</value>
                    <value>CCC</value>
                </list>
            </property>
            <!-- 注入 Map 数据 -->
            <property name="myMap">
                <map>
                    <entry key="testA" value="aaa"></entry>
                    <entry key="testB">
                        <value>bbb</value>
                    </entry>
                </map>
            </property>
            <!-- 注入 properties 数据 -->
            <property name="myProps">
                <props>
                    <prop key="testA">aaa</prop>
                    <prop key="testB">bbb</prop>
                </props>
            </property>
            </bean>
    
    • 注:这是entry的特有写法
        <entry key="testB">
            <value>bbb</value>
        </entry>
    

4. 附录

4.1 Spring 配置文件中提示的配置

4.2 详页连接

详页连接

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

狂野小白兔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值