Spring学习笔记(一)

Spring学习笔记(一)

​ MyBatis的学习已经告一段落了,持久层往上就到了服务层。服务层的技术便是我们顶顶大名的spring。

一、Spring概述

​ Spring是一款javaEE轻量级开源框架,以IOC(反转控制)和AOP(面向切面编程)为内核,提供了SpringMVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架,和类库,逐渐成为使用最多的JavaEE企业应用开源框架。

二、Spring的优势

1.方便解耦,简化开发

2.AOP编程的支持

3.声明式事务的支持

4.方便程序的测试

5.方便集成各种优秀框架

6.降低JavaEE的使用难度

7.Spring源码是经典的学习案例

三、程序耦合

​ 在讲解Spring的一大核心IOC之前,我们首先要弄明白什么是程序的耦合。

​ 在这里引入一小段耦合的概念,看不懂一笑而过即可。

在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计 应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个 准则就是高内聚低耦合。

用通俗的话来说,耦合就是程序尤其是对象之间的关联程度。关联程度越高,我们修改代码时,需要修改的地方就越多。这样既会导致维护成本提高,也会致使出错的概率提升。所以我们要尽量减少程序间的关联程度,即耦合度。

​ 耦合有以下分类:

1) 内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另 一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。

2) 公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大 量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。

3) 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传
递该全局变量的信息,则称之为外部耦合。

4) 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进 行适当的动作,这种耦合被称为控制耦合。

5) 标记耦合 。若一个模块 A 通过接口向两个模块 B 和 C 传递一个公共参数,那么称模块 B 和 C 之间
存在一个标记耦合。

6) 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形
式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另 一些模块的输入数据。

7) 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实
现的。

总结:耦合是影响软件复杂程度和设计质量的一个重要因素,在编写程序的过程中,我们应采取一下原则:如果模块间必须存在耦合,那么尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免内容耦合

四、程序解耦举例

​ 我们可以将解耦理解成一句话,即:做到程序编译器不报错,运行期才报错

​ 以JDBC基本操作为例,我们在注册驱动时可以采用以下的写法:

DriverManager.registerDriver(new com.mysql.jdbc.Driver());

​ 由于我们采用了new关键字,一旦我们将mysql驱动的jar包删除,这条语句将在编译器就会报错,这体现出JDBC与Driver类的耦合度过高。

​ 要想降低两者之间的耦合度,可以用反射的机制来注册驱动:

Class.forName("com.mysql.jdbc.Driver");//此处只是一个字符串

​ 采用这种写法,即使删除jar包,编译器也不会报错,这便实现了解耦。(当然程序是无法运行的,在运行期必然会报错。)

实际上一种更常见的解耦方式就是采用工厂模式来实现控制反转(IOC)

五、IOC–控制反转

​ 概念:

控制反转把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入和依赖查找

​ 作用:

削减计算机·程序的耦合,降低程序间的以来关系

​ 分析:

​ 原来我们获取对象时,采用new的方式,是主动去找

​ 现在我们获取对象时,是由工厂创建或查找得到的,是被动获得。

​ 这种控制权交给工厂的形式就叫做控制反转(IOC)

六、Spring中的IOC

​ Spring框架一大精妙之处就在于,能够帮助实现控制反转,通过配置bean对象,spring可以自动生成该对象的工厂,并且提供服务。这不仅有利于降低程序间的耦合,还大大提高了开发效率。

入门案例:

​ 通过spring中xml配bean的方式,实现dao与service对象的创建:

1.导入spring依赖

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

2.编写service与dao层的接口与实现类(省略)

3.配置bean.xml文件

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 把对象的创建交给spring来管理 -->
    <bean id="accountService" class="com.itheima.service.Impl.AccountServiceImpl"></bean>

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

4.创建使用bean对象

 public static void main(String[] args) {
        //获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //根据id获取bean对象
        IAccountService as = (IAccountService) ac.getBean("accountService");
        IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);

        System.out.println(as);
        System.out.println(adao);
    }

5.(成功)测试打印结果

com.itheima.service.Impl.AccountServiceImpl@5ea434c8
com.itheima.dao.Impl.AccountDaoImpl@3bbc39f8

值得注意的·是,根据id获取bean对象时,有两种方式进行类型转换:

1.强制类型转换

2.传入转后类型的字节码作为参数

六、SpringIOC的细节与bean标签

1.beanFactory与ApplicationContext的联系与区别:

​ BeanFactory是Spring的顶层接口,ApplicationContext是BeanFactroy的底层接口

​ ApplicationContext接口的实现类:

​ (1)ClassPathXmlApplicationContext:

​ 从类的根路径下加载配置文件 (推荐使用)

​ (2)FileSystemXmlApplicationContext:

​ 从磁盘的路径下加载配置文件,配置文件可以在磁盘的任意位置

​ (3)AnnotationConfigApplicationContext:

​ 使用注解配置容器对象时,需要此类来创建spring容器。它用来读取注解

​ BeanFactroy与ApplicationConext的创建对象的时间不同:

​ (1)BeanFactory只有当对象被使用的时候,才会创建对象(延迟加载)

​ (2) ApplicationConext只要加载配置文件,就会创建对象(立即加载)

2.bean标签

作用:

​ 用于配置对象,以便Spring创建。

默认情况下它调用对象类中的无参构造函数。如果没有无参构造函数则创建失败

属性:

​ (1)id:给对象在容器中提供唯一标识。用于获取对象

​ (2)class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数

​ (3)scope:指定对象的作为范围:

​ a) singleton: 默认值,单例的

​ b) prototype: 多例的

​ c) request: WEB项目中,Spring创建一个Bean对象,将对象存到request域中

​ d)session:在WEB项目中,Spring创建一个Bean对象,将对象存到session域中

​ e)globalSession:WEB项目中,运行在Portlet环境中,如果没有Protlet环境, globalSession相当于session

​ (4) init-method:指定类中的初始化方法名称

​ (5) destroy-method:指定类中的销毁方法名称

bean对象的作用范围与生命周期:

单例对象:scope=“singleton”:

​ 一个应用只有一个对象的实例。作用范围即整个应用

​ 生命周期:

​ 对象出生:当应用加载,创建容器时,对象就被创建了

​ 对象活着:只要容器在,对象一直活着

​ 对象死亡:当应用卸载,销毁容器时,对象就被销毁了

多例对象:scope=“protoType”:

​ 每次对象访问的时候,都会重新创建对象实例

​ 生命周期:

​ 对象出生:当使用对象时,新的对象被创建

​ 对象活着:只要对象在使用中,就一直活着

​ 对象死亡:当对象长时间不用时,被java垃圾回收器回收了

实例化bean对象的三种方式:

​ (1)使用默认无参构造函数:

<!--在默认情况下:
它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。--> 
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>

​ (2)spring管理工厂–使用实例工厂的方法创建对象(当我们要创建jar包中的类时,这个类又没有无参构造函数,常常使用这种方式)

<!-- 此种方式是:
先把工厂的创建交给 spring 来管理。
然后在使用工厂的 bean 来调用里面的方法 
factory-bean 属性:用于指定实例工厂 bean 的 id。
factory-method 属性:用于指定实例工厂中创建对象的方法。
-->
<bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="accountService"
      factory-bean="instancFactory"
      factory-method="createAccountService"></bean>
						(3)  spring静态管理工厂--使用静态工厂的方法创建对象:  
<!-- 此种方式是:
 	使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器 
	id 属性:指定 bean 的 id,用于从容器中获取 
	class 属性:指定静态工厂的全限定类名
	factory-method 属性:指定生产对象的静态方法
-->
<bean id="accountService"
      class="com.itheima.factory.StaticFactory"
      factory-method="createAccountService"></bean>

七、Spring的依赖注入

依赖注入:Dependency Injection。它是Spring框架核心IOC的具体体现

​ 我们在程序编写时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。IOC解耦只是降低耦合度,但不会消除耦合。例如我们的业务层仍会调用持久层的方法。

​ 那这种业务层和持久层的依赖关系,在使用Spring之后,就让Spring去维护了/

​ 简答的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

Spring依赖注入的三种规范方式:

(1)构造函数注入:

​ 顾名思义,即通过调用使用类中的构造函数,给成员变量赋值。

​ 例如某个AccountService类如下:

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;
	}
}

​ 注入方式:

<!-- 使用构造函数的方式,给 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.Data"></bean>

(2)set方法注入:

​ 顾名思义,就是在类中提供需要注入成员的set方法。

​ 例如某个AccountService类如下:

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;
	}
}

​ 注入方式如下;

<!-- 通过配置文件给 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>

(3)使用p名称空间注入数据(本质还是调用set方法)

​ 此种方式是通过在xml种导入p名称空间,使用p:propertyName来注入数据,它的本质仍是调用类中的set方法实现注入功能。

​ AccountService类同上

​ 注入方式:

<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="accountService" 
      class="com.itheima.service.impl.AccountServiceImpl4"
      p:name="test" p:age="21" p:birthday-ref="now"/>
</beans>	

(4)注入集合属性

​ 顾名思义,就是给类种的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。我们这里介绍注入数组,List,Set,Map,Properties。

​ 例如某AccountService类如下:

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;
	}
}

​ 注入方法:

!-- 注入集合数据 
	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"> 
        <props> 
            <prop key="testA">aaa</prop> 
            <prop key="testB">bbb</prop>
		</props>
	</property> 
    <!-- 注入 properties 数据 -->
    property name="myProps"> 
    	<map> 
            <!-- 方式1 -->
        	<entry key="testA" value="aaa"></entry> 
        	<!-- 方式2 -->
            <entry key="testB"> 
            	<value>bbb</value>
			</entry>
    	</map>
    </property>
</bean>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值