Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。
一站式框架:有SE/EE开发的每一层解决方案
WEB层:SpringMVCService层:Spring的Bean管理,Spring声明式事务DAO层:Spring的JdbcTemplate,Spring的ORM模块1.轻量
2.控制反转(IoC):解决程序之间的耦合
3.面向切面
**IOC(Inversion of Control)**控制反转:将对象的创建权交给Spring。
官网地址:https://spring.io/
Docs:Spring的开发规范和api
libs:Spring开发的jar包和源码
schema:Spring配置文件的约束
创建对象
UserDao dao = new UserDao(); //面向接口编程:方便程序的扩展 //缺陷:接口和实现类有耦合(联系过于紧密,切换底层实现类,必须修改底层源代码) UserDao dao = new UserDaoImpl();好的程序设计必须满足OCP原则,在尽量不修改程序源码的基础上对程序进行扩展
解决方式1:工厂模式,把所有类的创建交给工厂
UserDao dao = DaoFactory.getUserDao(); //接口和实现类之间没有耦合,但是接口和工厂有耦合。解决方式2:工厂+反射+配置文件,实现程序的解耦合(Spring IoC的底层实现原理)
<bean id="userDao" class="xxx.UserDaoImpl"></bean> class BeanFactory{ public static Object getBean(String id){ //解析XML,通过id查找class //反射 Class class = Class.forName(); return class.newInstance(); } }在src目录下新建applicationContext.xml(可以是其他名字,默认):
约束文件在spring-framework-4.2.4.RELEASE-dist\spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html中寻找the beans schema
<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">applicationContext.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"> <!-- Spring入门配置 --> <bean id="userDao" class="com.nike.spring.demo01.UserDaoImpl"></bean> </beans>log4j配置文件:log4j.properties
### direct log messages to stdout ### log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.err log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### direct messages to file mylog.log ### log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.File=c\:mylog.log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### set log levels - for more verbose logging change 'info' to 'debug' ### # error warn info debug trace log4j.rootLogger= info, stdoutIoC:控制反转,将对象的创建权反转给了Spring
DI:依赖注入,前提必须要有IoC的环境,Spring在管理这个类的时候将类的依赖属性注入(设置)进来
依赖:A类在B类的某一个方法中做参数,要将A类的实例传入B类的方法
继承:extends,is a,
聚合:has a,A类是B类的一个属性,松散,紧密
package com.nike.spring.demo01; /** * 用户管理业务逻辑层的一个实现类 * @author 猪猪 */ public class UserDaoImpl implements UserDao { private String name; public void setName(String name){ this.name = name; } public void save() { System.out.println("UserService执行了..."+name); } } <?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"> <!-- Spring入门配置 --> <bean id="userDao" class="com.nike.spring.demo01.UserDaoImpl"> <property name="name" value="lisi"/> </bean> </beans> package com.nike.spring.demo01; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Spring的入门 * @author 猪猪 */ public class SpringDemo1 { /** * 传统方式的调用 */ @Test public void demo1(){ UserDaoImpl dao = new UserDaoImpl(); dao.setName("zhangsan"); dao.save(); } @Test /** * Spring方式的调用 * */ public void demo2(){ //创建Spring工厂 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao dao = (UserDao) applicationContext.getBean("userDao"); dao.save(); } }Spring提供了两个工厂类:ApplicationContext,BeanFactory
区别:
BeanFactory是Spring工厂类的最上层结构,ApplicationContext继承了BeanFactory接口
ApplicationContext有两个具体实现类,FileSystemXmlApplicationContext和ClassPathXmlApplicationContext
BeanFactory:调用getBean()方法的时候才会生成类实例。
ApplicationContext:加载配置文件时就会将Spring管理的类都实例化。
加载文件系统下的配置文件(本地磁盘)。
加载类路径下的配置文件。src目录下的配置文件,最终会翻译到class目录下
一个xml只能被一个DTD约束,可以被多个Schema约束。
id:使用了约束中的唯一约束,里面不能出现任何特殊字符,
name:没有使用约束中的唯一约束(理论上可以出现重复,实际开发中不能重复),name中可以出现特殊字符。
在Spring和Struts1整合时可能会出现特殊字符。<bean name="/user" class=“xxx”>
class:要生成实例的类的全路径。
init-method:Bean初始化时执行的方法
destory-method:Bean被销毁的时候执行的方法(Bean时单例创建的,默认就是单例创建,工厂关闭,Bean销毁)
scope:代表Bean的作用范围,取值有:
singleton:默认的,采用单例模式创建这个对象(主要)
prototype:多例模式,(主要,Struts2和Spring整合时一定会用到)
request:应用在Web项目中,Spring创建这个类实例后,会将这个实例存入到request范围中。
session:应用在Web项目中,Spring创建这个类实例后,会将这个的类实例存入到session域中。
globalsession:应用在Web项目中,必须在porlet环境下才能使用,如果没有这种环境,相当于存入session域中。
/** * 作用范围的配置 */ @Test public void demo02(){ ApplicationContext aContext = new ClassPathXmlApplicationContext("applicationContext.xml"); CustomDao bean1 = (CustomDao) aContext.getBean("customDao"); CustomDao bean2 = (CustomDao) aContext.getBean("customDao"); CustomDao bean3 = (CustomDao) aContext.getBean("customDao"); System.out.println(bean1); System.out.println(bean2); System.out.println(bean3); } //CustomDaoImpl的实例创建了 //com.nike.spring.demo02.CustomDaoImpl@63440df3 //com.nike.spring.demo02.CustomDaoImpl@63440df3 //com.nike.spring.demo02.CustomDaoImpl@63440df3 //只初始化一次,并且三个对象的地址值一致给Bean中的属性设置值的方式有3种:
Spring提供了2大类的属性注入方式:
使用构造方法同样可行。
SpEL(Spring Expression Language)
Spring的表达式语言
#{SpEL}
<!-- SpEL表达式完成属性注入 --> <bean id="car002" class="com.nike.spring.demo03.Car2"> <property name="name" value="#{'布加迪威龙'}"/> <property name="price" value="#{5489741}"/> </bean> <!-- SpEL表达式完成属性注入 --> <bean id="car002" class="com.nike.spring.demo03.Car2"> <property name="name" value="#{'布加迪威龙'}"/> <property name="price" value="#{5489741}"/> </bean> <bean id="employee01" class="com.nike.spring.demo03.Employee"> <!-- value使用来设置普通类型的值,ref是用来设置其他类的id或name --> <property name="name" value="工程师"/> <property name="car2" value="#{car002}"></property> </bean> package com.nike.spring.demo03; public class CarInfo { private String carName; public String getCarName() { return "三蹦子"; } public Double getPrice(){ return Math.random()*3000; } } <bean id="carinfo" class="com.nike.spring.demo03.CarInfo"></bean> <bean id="car0002" class="com.nike.spring.demo03.Car2"> <property name="name" value="#{carinfo.getCarName()}"/> <property name="price" value="#{carinfo.getPrice()}"/> </bean>将Spring的配置文件分成多个
applicationContext2.xml
<?xml version="1.0" encoding="UTF-8"?> <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"> <!-- Spring的集合属性注入 --> <!-- 注入列表 --> <bean id="collectionBean" class="com.nike.spring.demo04.CollectionBean"> <property name="strs"> <!-- 注入列表类型和数组类型一致 --> <list> <value>野犬</value> <value>你可</value> <value>杰神</value> <value>马克</value> </list> </property> <property name="ins"> <list> <value>1</value> <value>2</value> <value>3</value> <value>4</value> </list> </property> <property name="cars"> <list> <ref bean="car2"/> <ref bean="car02"/> <ref bean="car002"/> <ref bean="car0002"/> </list> </property> <!-- 注入set集合 --> <property name="set"> <set> <value>马云</value> <value>李彦宏</value> <value>马化腾</value> <value>雷军</value> </set> </property> <!-- 注入Map集合 --> <property name="map"> <map> <entry key="1" value="jack"></entry> <entry key="2" value="mike"></entry> <entry key="3" value="rose"></entry> <entry key="4" value="lucy"></entry> </map> </property> </bean> </beans>applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <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"> <!-- Spring入门配置 --> <bean id="userDao" class="com.nike.spring.demo01.UserDaoImpl"> <property name="name" value="lisi"/> </bean> <!-- Spring bean的生命周期的配置 --> <bean name="customDao" class="com.nike.spring.demo02.CustomDaoImpl" scope="prototype" init-method="init" destroy-method="destory"></bean> <!-- 配置car类并完成属性注入(构造方法) --> <bean id="car" class="com.nike.spring.demo03.Car"> <constructor-arg name="name" value="保时捷"/> <constructor-arg name="price" value="800000"/> </bean> <!-- 配置Car2类并完成属性注入(setXxx()方法) --> <bean id="car2" class="com.nike.spring.demo03.Car2"> <property name="name" value="兰博基尼"/> <property name="price" value="140000000"/> </bean> <!-- 引入p名称空间的方式完成属性注入 --> <bean id="car02" class="com.nike.spring.demo03.Car2" p:name="法拉利" p:price="1545665"></bean> <!-- set方法注入对象类型的属性 --> <bean id="employee" class="com.nike.spring.demo03.Employee"> <!-- value使用来设置普通类型的值,ref是用来设置其他类的id或name --> <property name="name" value="工程师"/> <property name="car2" ref="car2"></property> </bean> <!-- 引入p命名空间完成引用类型的属性注入 --> <bean id="employee1" class="com.nike.spring.demo03.Employee" p:name="胡卫平" p:car2-ref="car02"></bean> <!-- SpEL表达式完成属性注入 --> <bean id="car002" class="com.nike.spring.demo03.Car2"> <property name="name" value="#{'布加迪威龙'}"/> <property name="price" value="#{5489741}"/> </bean> <bean id="employee01" class="com.nike.spring.demo03.Employee"> <!-- value使用来设置普通类型的值,ref是用来设置其他类的id或name --> <property name="name" value="工程师"/> <property name="car2" value="#{car002}"></property> </bean> <bean id="carinfo" class="com.nike.spring.demo03.CarInfo"></bean> <bean id="car0002" class="com.nike.spring.demo03.Car2"> <property name="name" value="#{carinfo.getCarName()}"/> <property name="price" value="#{carinfo.getPrice()}"/> </bean> <!-- 使用import标签引入其他配置文件 --> <import resource="applicationContext2.xml"/> </beans>