- spring框架
1. Spring是分层的Java SE/EE应用 full-stack轻量级开源框架
以IoC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核
提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术
还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架
2. Spring优势:
a. 方便解耦,简化开发:
降低程序之间的依赖
应该做到编译期不依赖,运行期才依赖
例如:
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
b. AOP编程的支持
c. 声明式事务的支持
d. 方便程序测试
e. 方便集成各种框架
f. 降低JavaEE API使用难度
g. Java源码是经典的学习范例
3. 程序的耦合:
a. 程序间的依赖关系:程序的编译依赖于其他的程序
1. 类之间的依赖
2. 方法之间的依赖
b. 解耦思想:
1. 使用反射来创建对象,而避免使用new关键字
2. 通过读取配置文件来获取要创建的对象的全限定类名
c. 开发中应用:
1. 创建工厂类来生产Bean对象:
Bean在计算机英语中表示可重用组件
2. JavaBean:
JavaBean指用Java语言编写的可重用组件
JavaBean范围远大于实体类
3. 需要一个配置文件来配置需要生产的Bean对象
配置内容:唯一标识=全限定类名(key=value)
4. 通过读取配置文件配置的内容,反射创建对象
配置文件可以使用xml或properties文件
Object obj = Class.forName(beanPath).newInstance();
* 每次调用newInstance方法都会调用一次默认构造函数
* 此时创建的对象形式为多例的
5. 工厂类的构建:
* 创建一个静态私有的Properties对象用于加载配置文件
* 创建一个静态容器Map对象用于保存配置文件中要求的对象
* 在static静态代码块中读取配置文件,利用反射创建对象,将配置文件中的key和新创建的对象存储Map容器
* 在静态方法中返回Map容器中早已创建好的对象
* 由于静态代码块仅在类加载时执行一次,因此该工厂调用成员方法创建的对象都是同一个,对象为单例形式
6. 使用工厂生产Bean对象先决条件:
业务层和持久层中几乎可以改变的成员变量
- IoC控制:Inverse Of Control 反转控制
1. 原始创建对象形式:
由app寻找资源,然后创建对象(new形式)
2. 控制反转创建形式:
由app向工厂索要对象,工厂控制资源(工厂类形式)
将原本自主创建对象的权力交予工厂,即控制反转。包括依赖注入和依赖查找
- 使用spring的IOC解决程序耦合
1. 下载解压spring framework:
spring-framework-5.0.2.RELEASE-dist
2. 导入相关spring相关jar包:
spring-aop-5.0.2.RELEASE.jar -- 基于注解开发的必备jar包
spring-beans-5.0.2.RELEASE.jar -- 中间4个为核心容器的jar包
spring-context-5.0.2.RELEASE.jar
spring-core-5.0.2.RELEASE.jar
spring-expressoin-5.0.2.RELEASE.jar
spring-jcl-5.0.2.RELEASE.jar -- 集成了apache的日志组件做成了自己的jar包
使用坐标定位时仅需要定位spring-context即可:
* 当前工程依赖于spring-context
* spring-context依赖于spring-beans,spring-aop,spring-expression,spring-core
* spring-aop依赖于spring-beans,spring-core
* spring-beans依赖于spring-core
* spring-expression依赖于spring-core
* spring-core依赖于spring-jcl
3. 创建xml配置文件,并导入约束:
/resource/bean.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.xsd">
<!--配置相关信息-->
</beans>
4. 使用bean标签将对象的创建交给框架:
<bean id="唯一标识key" class="需要创建的对象的全限定类名"></bean>
5. 获取spring核心容器,并根据id获取创建的对象:
ApplicationContext coreObj = new ClassPathXmlApplicationContext("配置文件名(bean.xml)")
E element = (E) coreObj.getBean("唯一标识id");
* 获取核心容器的三种形式:
1. ClassPathXmlApplicationContext:仅能加载类路径下的配置文件
2. FileSystemXmlApplicationContext:可以加载任意磁盘路径下的配置文件(需要有访问权限)
3. AnnotationConfigApplicationContext:用于读取注解创建容器
* 核心容器的两个接口:
1. ApplicationContext:单例对象适用,但是可以根据配置设置立即或延迟,因此开发更为常用
在构建核心容器时,创建对象为立即加载方式。即,读取完配置文件后,立即创建所有配置中的对象
2. BeanFactory:多例对象适用
在构建核心容器时,创建对象为延迟加载方式。即,仅由id获取对象时创建该对象
6. spring对Bean的管理细节:
a. 创建bean的三种方式:
1. 使用默认构造函数创建对象:
在spring的配置文件中使用bean标签,配置id和class属性,且没有其他属性和标签,调用默认构造函数创建
<bean id="唯一标识key" class="需要创建的对象的全限定类名"></bean>
如果此时类中没有默认构造函数(重写了带参构造函数但是没有重写默认构造函数),则不能创建bean对象
2. 使用其他类中的方法创建对象:
在spring的配置文件中使用bean标签,配置id,factory-bean,factory-method属性,调用工厂类中方法创建
<bean id="唯一标识key" class="创建对象的工厂的全限定类名"></bean>
<bean id="唯一标识key" factory-bean="工厂唯一标识id" factor-method="创建对象的方法"></bean>
3. 使用其他类中的静态方法创建对象:
在spring的配置文件中使用bean标签,配置id,class,factory-method属性,调用工厂类中静态方法创建
<bean id="唯一标识key" class="工厂全限定类名" factor-method="创建对象的静态方法"></bean>
b. bean对象的作用范围:
1. 默认情况下,bean标签创建对象的形式是单例的
2. 通过bean标签的scope属性来指定bean的作用范围:
* singleton:单例的(默认值)
* prototype:多例的
* request:作用于web应用的请求范围
* session:作用于web应用的会话范围
* global-session:作用于集群环境的会话范围(全局会话范围),当不是集群范围时,等同于session范围
c. bean对象的生命周期:
1. 单例对象:
生命周期与容器相同:容器创建时创建,容器销毁时销毁
调用ClassPathXmlApplicationContext的close方法销毁容器
2. 多例对象:
生命周期:使用对象时spring框架创建,当对象长时间没有使用且无其他对象引用时有java垃圾回收机制回收
7. spring中的依赖注入:
a. 依赖关系管理:
表示层调用业务层,业务层调用持久层这是必然会出现的
于是将调用间的对象创建交由spring,这种依赖关系有spring管理
我们只需要在配置文件中说明,在当前类中需要使用其他类的对象,其他类的对象有spring提供
依赖关系的维护称为:依赖注入
b. 能够注入的数据:
1. 基本类型和String
2. 其他bean类型(在配置文件中或者注解配置过的bean)
3. 复杂类型/集合类型
c. 注入方式:
1. 使用构造函数
被注入的类中重写了带参构造函数时,在bean标签的配置内部加入constructor-arg标签
<bean id="唯一标识key" class="需要创建的对象的全限定类名">
<constructor-arg></constructor-arg>
<!--
constructor-arg标签中的属性:
* type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
* index:用于指定注入数据在构造函数中参数的索引,从0开始
* name:用于指定注入数据在构造函数中的名称 (常用形式)
=======================以上3个属性用于确定给构造函数中哪个参数赋值==================
* value:指定参数注入的值,仅限基本类型和String类型
* ref:用于引用关联的bean对象,仅限IOC容器中配置过的对象
-->
</bean>
例如:
当需要注入的参数为Date类型数据时,并不能直接使用value赋值一个字符串
而需要另外定义一个bean对象,反射创建一个Date对象,用constructor-arg的ref属性引用创建的Date对象
<bean id="now" class="java.util.Date"></bean>
<bean id="xxx" class="xxx.xxx.xxx">
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
优势:
由于没有默认构造函数,所以创建对象时,配置注入参数的操作是必须的,否则无法创建对象
劣势:
改变了bean对象的实例化方式,如果不使用该bean对象也同样需要配置参数注入
2. 使用set方法
被注入的类中必须含有参数的set方法,可以不写get方法。在bean标签内部使用property标签
<bean id="唯一标识key" class="需要创建的对象的全限定类名">
<property></property>
<!--
property标签中的属性:
* name:用于指定注入数据在set方法中的属性名称
* value:指定参数注入的值,仅限基本类型和String类型
* ref:用于引用关联的bean对象,仅限IOC容器中配置过的对象
-->
</bean>
优劣与构造方法创建相反
复杂数据类型注入:
* 给List结构的参数注入:
在property内部有子标签list,set,array,在通过子标签的子标签<value></value>进行元素赋值
<property name="myList">
<list>
<value>索引为0的值</value>
<value>索引为1的值</value>
...
</list>
</property>
* 用于给map结构的参数注入:
在property内部有子标签map,propos,在通过子标签的key和value为元素赋键值
<property name="myMap">
<map key="键" value="值"></map>
</property>
* 相同结构的注入操作标签可以互换,即List可以使用set/list/array标签都行
3. 使用注解
- 举例:使用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.xsd">
<!-- 配置Service -->
<bean id="accountService" class="cn.mysilent.service.impl.AccountServiceImpl">
<!-- 注入dao -->
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--配置Dao对象-->
<bean id="accountDao" class="cn.mysilent.dao.impl.AccountDaoImpl">
<!-- 注入QueryRunner -->
<property name="runner" ref="runner"></property>
</bean>
<!--配置QueryRunner,为了使每个查询不相互干扰,配置该对象的创建为多例prototype-->
<!--如果QueryRunner是单例对象,则面临多个dao使用时,可能引发线程安全问题-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!--注入数据源-->
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--连接数据库的必备信息-->
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="用户名"></property>
<property name="password" value="密码"></property>
</bean>
</beans>