Spring版本号的问题
- spring5是2017年9月发布通用版本,是自2013年12月以来第一个主要的Spring版本,兼容JavaEE8 (Servlet4、Bean Validation 2.0)和 JDK9,集成了反应式编程Rx模型(完全异步和非阻塞的)支持
- Spring6开始,已经升级到 Jakarta EE 9 级别(例如 Servlet 5.0+、JPA 3.0+),基于 Jakarta 命名空间而不是传统的javax包。要求使用 Java 17 或更高版本,由于Jakarta EE 9是最低的,Jakarta EE 10已经得到支持,Spring 准备为 Jakarta EE API 的进一步发展提供开箱即用的支持。SpringFramework 6.0 与 Tomcat 10.1、Jetty 11 和 Undertow 2.3 作为 web 服务器完全兼容,也与Hibernate ORM 6.1 完全兼容
相关版本号
- Snapshot快照版:尚不稳定,尚处于开发中的版本
- M1中M是Milestone里程碑的意思。代表功能可能还不完整,可能存在一些问题。
- RC1中的RC是 Release Candidate发布候选版。代表功能完整且相对稳定,主要进行问题解决
- GA是 General Availability一般可用版,代表稳定可用于生产的版本。
工厂模式
工厂模式Factory Pattern是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提
供了一种创建对象的最佳方式。在工厂模式中,在创建对象时不会对客户端暴露创建逻辑,并且是通过
使用一个共同的接口来指向新创建的对象。
**意图:**定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程
延迟到子类进行。
**主要解决:**主要解决接口选择的问题。
**何时使用:**我们明确地计划不同条件下创建不同实例时。
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
**缺点:**每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增
加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
接口
public interface Shape{
public void draw();
}
多种实现
public class Circle implements Shape{}
public class Square implements Shape{}
public class Rectangle implements Shape{}
最终目标还是需要使用某个实现,但是为了解除耦合引入工厂类,传递工厂类一个名称,由工厂类封装了具体的创建对象流程
public class ShapeFactory {
//使用 getShape 方法获取形状类型的对象
public Shape getShape(String shapeType){
if(shapeType == null) return null;
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
调用Shape类型的对象时,调用方并不需要了解具体的实现类,只需要一个名称参数即可
public class Test{
public static void main(String[] args){
Shape shape=ShapeFactory.getShape("circle");
shape.draw():
}
}
这个模式最大的优势在于允许产品扩展
public class MyShape implements Shape{} --- 新产品
扩展产品只需要添加一个对应的工厂类即可
public class MyFactory extends ShapeFactory{
public Shape getShape(String shapeType){
if("my".equalsIgnoreCase(shapeType))
return new MyShape();
else
return super.getShape(shapeType);
}
}
产品可以扩展,但是产品的系列不可扩展,同时可以会导致类爆炸问题
抽象工厂模式
抽象工厂模式Abstract Factory Pattern是围绕一个超级工厂创建其他工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
**意图:**提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
**主要解决:**主要解决接口选择的问题。
**何时使用:**系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
**优点:**当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族
中的对象。
**缺点:**产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又
要在具体的里面加代码。
两种不同系列的产品
两种不同系列
public interface Shape{}
public interface Color{}
Shape系列的不同产品
public class Circle implements Shape{}
public class Square implements Shape{}
public class Rectangle implements Shape{}
Color系列的不同产品
public class Red implements Color{}
public class Green implements Color{}
不同产品系列定义对应的工厂 —产品接口
public abstract class AbstractFactory{
public abstract Color getColor(String color);
public abstract Shape getShape(String shape) ;
}
具体的工厂----只能生产一个系列的产品
public class ShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
@Override
public Color getColor(String color) {
return null;
}
}
工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
抽象工厂的使用
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE"); //获取形状工厂
Shape shape1 = shapeFactory.getShape("CIRCLE"); //获取形状为 Circle 的对象
工厂模式改进1:引入properties配置
产品编程部分没有任何修改 接口—实现类
public interface IUserDao{}
public class MySQLUserDao implements IUserDao{}
添加一个properties文件用于解除耦合 key=具体实现类的全名
userDao=com.yan.dao.MySQLUserDao
添加一个工厂类用于创建对象,这里将使用Class.for(“类的全名”).newInstance()创建指定全名的类对象
public class BeanFactory {
private static final Properties ps = new Properties();
static { //类加载时自动执行,且只执行一次,所以不存在线程安全问题
try {
InputStream inputStream = BeanFactory.class
.getResourceAsStream("beans.properties"); //要求beans.properties和BeanFactory类位
置相同
ps.load(inputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object getBean(String name) {
try {
if (!ps.isEmpty()) {
if (ps.containsKey(name)) {
String className = ps.getProperty(name);
if (className != null && className.trim().length() > 0) {
//优势1:每次获取对象时都是新建,如果不是属性,则线程安全
return Class.forName(className).newInstance(); } }//
通过反射使用无参构造器创建对象,所以类定义中必须有无参构造器
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
如果添加新产品,则不需要修改任何已经定义好的类
public class OracleUserDaoImpl implements IUserDao{} //新产品
修改properties文件
userDao=com.yan.dao.OracleUserDaoImpl
不用修改其它位置,在代码中已经实现从MySQLUserDaoImpl切换到OracleUserDaoImpl的效果
问题是:针对properties文件在IDE工具中不能进行有效的检查
工厂模式改进2:引入xml配置
xml即可扩展标记语言,xml是互联网数据传输的重要工具,它可以跨越互联网任何的平台,不受编程语言和操作系统的限制,可以说它是一个拥有互联网最高级别通行证的数据携带者。xml是当前处理结构化文档信息中相当给力的技术,xml有助于在服务器之间穿梭结构化数据,这使得开发人员更加得心应手的控制数据的存储和传输。
Xml用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。Xml是标准通用标记语言SGML的子集,非常适合Web传输。XML提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。
XML特点
- xml是一种无格式纯文本文件,xml与操作系统、编程语言的开发平台都无关;
- 实现不同系统之间的数据交互。
XML作用 - 配置应用程序和网站;在配置文件里边所有的配置文件都是以XML的格式来编写的
- 可以用于跨语言、跨平台的数据交互;是Ajax基石。
xml文件的验证机制 - dtd文档类型定义——Document Type Definition
- schema类型定义xsd——xml Schema是用一套预先规定的xml元素和属性创建的
xml文件有3种 - 良构:这个xml文件的内容,完全按照xml语言要求的语法进行的编写符合语法,符合基本的规范要求
- 有效:在良构的基础之上,那么这个xml同时还要满足DTD或者Schame文件的约束
- 无效:不遵守基本规则
解析XML文件的规范 - SAX即Simple API for XML是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备。SAX解析XML文件采用的是事件驱动,也就是说并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件
-
- 所谓事件就是一些回调callback方法,这些方法(事件)定义在ContentHandler接口
- DOM解析XML文件时,会将XML的所有内容读取到内存中,然后允许您使用DOM API遍历XML树、检索所需的数据。因为DOM需要将所有内容读取到内存中,所以内存的消耗比较大,不建议使用DOM解析XML文件,若文件较小可行。
JAXP
为了让应用程序不依赖于具体的解析器,以统一的接口来访问XML文档,Sun公司开发了JAXP,Java API
for XMLProcessing意为XML处理的Java API
JAXP没有扩充解析器新的功能,它是对解析器的一个封装,使开发能够独立于具体的解析器,这样就可
以在应用程序中任意更换解析器,而不用更改应用程序代码。现在主流的解析器都支持DOM和SAX,所
以JAXP也都支持。JAXP现在的版本是1.3包含在JDK5.0之中
SAX的编程处理
SAXParserFactory factory=SAXParserFactory.newInstance(); //创建SAX解析器工厂
//通过解析器工厂创建对应解析器的引用,具体的解析器已经在系统中完成完成,如果不能获取解析器则出异
常
SAXParser parser=factory.newSAXParser();
//获取用于读取books.xml文件的输入流
InputStream inputStream=Test1.class.getResourceAsStream("books.xml");
//定义对应的事件回调处理
parser.parse(inputStream,new DefaultHandler(){
//开始进行文档解析时的回调方法
public void startDocument() throws SAXException {
System.out.println("开始解析books.xml文件");
}
//一个标签一般包括标签头 标签体 标签尾三部分,例如<p>aaaa</p>
//当SAX读取到标签头时的回调处理
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// uri用于区分标签--标签的名空间,localName是标签的本地名,qName是标签的全局名,
attributes是当前标签的所有属性
System.out.println("遇到标签头<"+qName+">");
}
//遇到标签体的回调处理,SAX会将读取到的标签体内容存储在ch数组中,从start位置开始,总
length个长
public void characters(char[] ch, int start, int length) throws SAXException
{
String ss=new String(ch,start,length);
System.out.println("读取的标签体内容为:"+ss);
}
//遇到标签尾的回调处理方法
public void endElement(String uri, String localName, String qName) throws
SAXException {
System.out.println("遇到标签结尾</"+qName+">");
}
//解析完毕时的回调处理
public void endDocument() throws SAXException {
System.out.println("文件解析完毕");
}
});
inputStream.close();
SAX是以事件流的方式解析xml文件,所以需要开发人员自行缓存数据
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="a1">
<title>Java入门</title>
<author>十一</author>
<price>12.34</price>
</book>
<book id="a2">
<title>Java编程思想</title>
<author>国庆</author>
<price>102.34</price>
</book>
</books>
这里的结构化特征很明显,所以可以针对一个 定义一个BookBean,然后解析xml文件将数据存储在一个一个的bookBean对象中即可
public class BookBean {
private String id;
private String title;
private String author;
private Double price;
}
具体的SAX解析编程
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
InputStream inputStream=Test1.class.getResourceAsStream("books.xml");
List<BookBean> list = new ArrayList<>();
parser.parse(inputStream,new DefaultHandler(){ //匿名内部类
private BookBean bookBean = null;
private int flag=0;
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if("book".equals(qName)){
bookBean=new BookBean();
String id=attributes.getValue("id");
if(id!=null && id.trim().length()>0)
bookBean.setId(id.trim());
}else if("title".equals(qName))
flag=1;
else if("author".equals(qName))
flag=2;
else if("price".equals(qName))
flag=3;
}
public void characters(char[] ch, int start, int length) throws SAXException
{
String ss=new String(ch,start,length);
if(ss!=null && ss.trim().length()>0) {
if (flag == 1)
bookBean.setTitle(ss.trim());
else if(flag==2)
bookBean.setAuthor(ss.trim());
else if(flag==3){
try{
double dd=Double.parseDouble(ss.trim());
bookBean.setPrice(dd);
} catch(Exception e){
throw new SAXException(e);
}
}
}
}
//遇到标签尾的回调处理方法
public void endElement(String uri, String localName, String qName) throws
SAXException {
flag=0;
if("book".equals(qName)){
list.add(bookBean);
}
}
});
inputStream.close();
list.forEach(System.out::println);
将工厂中的properties改为xml配置文件
beans.xml声明bean
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userDao" class="com.yan.test.UserDaoImpl"/>
</beans>
bean工厂类
public class BeanFactory {
//容器,用于存储所有的bean对象,key是id名称
//事实上由于在使用时并不修改map,所以实际上没有必要进行安全性处理
private static Map<String, Object> map = new ConcurrentHashMap<>();
static {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
InputStream inputStream =
BeanFactory.class.getResourceAsStream("beans.xml");
parser.parse(inputStream, new DefaultHandler() {
@Override
public void startElement(String uri, String localName, String
qName, Attributes attributes) throws SAXException {
try {
if ("bean".equalsIgnoreCase(qName)) {
String id = attributes.getValue("id");
String className = attributes.getValue("class");
if (id != null && className != null) {
Object object =
Class.forName(className).newInstance();
map.put(id, object);
}
}
} catch (Exception e) {
throw new SAXException(e);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object getBean(String key) {
if (map.containsKey(key)) {
return map.get(key);
}
return null;
}
}
额外的福利:bean是单例的
Hello Spring
添加依赖 pom.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
在src/main/resources根目录下创建核心配置文件。针对文件命名没有特殊要求,一般命名为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">
<bean id="userDao" class="com.yan.test.UserDaoImpl"/>
</beans>
编程调用
//获取Spring的IoC容器引用
ClassPathResource resource = new ClassPathResource("applicationContext.xml");
BeanFactory factory=new XmlBeanFactory(resource);
//从容器中通过名称获取对应的bean对象,这个对象由Spring容器负责创建和管理
IUserDao userDao = (IUserDao) factory.getBean("userDao");
userDao.save();
Spring主要功能
- Spring是一个开源的依赖注入IoC和面向切面AOP的容器框架。它的主要目是简化企业级应用的开发
- Spring的IoC容器包含并管理应用对象的配置和生命周期,可以配置每个bean如何被创建,也可以配置每个bean是只有一个实例,还是每次需要时都生成一个新的实例以及它们是如何相互关联的
- Spring AOP提供了很多基础但是与业务逻辑无关的功能,比如事务管理、与持久化框架、显示层框架集成等
- Spring 还提供了自己的MVC实现,提供了模板类JdbcTemplate来简化数据操作
Spring的优点
- 降低组件之间的耦合度,实现软件各层之间的解耦
- 方便解耦,简化开发。Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理 spring工厂是用于生成bean
- AOP编程的支持。Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
- 声明式事务的支持。只需要通过配置就可以完成对事务的管理,而无需手动编程
- 方便程序的测试。Spring提供了对Junit4支持,可以通过注解方便的测试Spring程序
- 方便集成各种优秀框架。Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
- 降低JavaEE API的使用难度。Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
Spring框架4大原则
- 使用POJO进行轻量级和最小侵入式开发。POJO普通简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称
- 通过控制反转IoC、依赖注入DI和基于接口编程实现松耦合
- 通过AOP和默认惯例进行声明式编程
- 使用AOP和模板编程减少模式化代码
什么是IoC
IoC是由Spring IoC容器来负责对象的生命周期和对象之间的关系
简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。IoC理论提出的观点大体是这样的:
借助于“第三方”实现具有依赖关系的对象之间的解耦
2004年Martin Fowler给控制反转IoC取了一个更合适的名字叫做依赖注入Dependency Injection。所谓依赖注入,就是由IoC容器在运行期间动态地将某种依赖关系注入到对象之中
IoC解决编码依赖
学生管理系统
业务层
- 接口:供表现层调用,避免控制器和业务实现类耦合
public interface IUserServ{
public boolean login(User user);
}
- 实现类封装具体的业务逻辑
-
- 登录添加积分
-
- 登录成功后记录最新IP地址和时间
public class UserServImpl implements IUserServ{
private IUserDao userDao; // 定义对应的set方法
public boolean login(User user){
}
}
使用Spring IoC替代工厂类:把Service与Dao的依赖配置在Spring配置文件中
<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">
<!--
applicationContext.xml: 取代了前面的properties配置文件
不但可以配置bean信息,还可以配置bean的依赖
-->
<bean id="userService" class="com.yan.biz.UserServImpl">
<!--
ref 引用: 指向另一个id, 此处说明userService依赖userDao。userDao 属性是私有
的,必须通过set方法注入
-->
<property name="userDao" ref="userDaoImpl" />
</bean>
<!-- 配置userDao class是具体的数据访问逻辑bean -->
<bean id="userDaoImpl" class="com.yan.dao.UserDaoImpl" />
</beans>
测试基本IOC功能
public class IOCTest {
@Test
public void test01(){
/*
* Resource: Spring中用来获取资源的接口
* ClassPathResource:这个类标识从classpath获得的资源
*/
Resource resource=new ClassPathResource("applicationContext.xml");
/*
* BeanFactory:Spring的依赖注入容器的核心是Bean工厂,取代了我们自己写的工厂类
* Bean工厂负责管理组件和它们之间的依赖关系、创建对象的数量、是否延迟创建...
* 功能强大
* */
BeanFactory beanFactory=new XmlBeanFactory(resource);
// getBean: 通过name和id去查找实例化的对象,通过Spring容器拿出来的对象,具有依赖注入
功能
IUserServ userService=(IUserServ)beanFactory.getBean("userService");
User student=new User("test",13);
boolean bb=userService.login(student);
System.out.println(bb);
Assert.assertEquals(true,bb);
}
}
通过Spring的依赖注入功能,只需要拿到Spring的配置文件,然后采用BeanFactory来获取想要的Bean对象,代码中只声明了一个接口类型,例如UserService、UserDao而且只有在运行的时候才知道真正注入的对象,这样大大提高了代码的灵活性(消除了编译时依赖,让运行时依赖具体的接口类型,而且以后可以动态变化)。而且类与类之间的依赖都配置到了配置文件中,查看关系一目了然。这就是Spring带来的IOC功能
为什么要用IoC
- 对象的实例化不是一件简单的事情,比如对象的关系比较复杂,依赖关系往往需要程序员去维护,这是一件非常头疼的事
- 解耦,由容器去维护具体的对象
- 托管了类的产生过程,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分过程交给容器,应用程序则无需去关心类是如何完成代理的
举个例子:使用连接池
添加依赖:druid
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="ds" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
IoC的两种实现
依赖查找DL和依赖注入DI
依赖查找Dependency Lookup:容器中的受控对象通过容器的API来查找自己所依赖的资源和协作对象。这种方式虽然降低了对象间的依赖,但是同时也使用到了容器的API,造成了耦合容器,无法在容器外使用和测试对象。 依赖查找是一种更加传统的IoC实现方式
依赖注入Dependency Injection:依赖注入就是将服务注入到使用它的地方。对象只提供普通的方法让容器去决定依赖关系,容器全权负责组件的装配,它会把符合依赖关系的对象通过属性(JavaBean中的setter)或者是构造子传递给需要的对象
获取Resource几种方式
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(“配置文件”));
接口的全名为org.springframework.core.io.Resource。比较常用的资源定义的实现类为:
DI和IoC
依赖注入DI和控制反转IoC是从不同的角度的描述的同一件事情,就是指通过引入IoC容器,利用依赖关
系注入的方式,实现对象之间的解耦。
Spring框架的功能被有组织的分散到约20个模块中共6大模块。这些模块分布在核心容器,数据访问/集成,Web,AOP面向切面的编程,植入Instrumentation消息传输和测试 。Spring采用模块化的结构,可以只使用需要的Spring的模块,每个模块各司其职,可结合需求引入相关依赖Jar包实现功能。
Spring Core Container
模块作用:Core 和 Beans 模块是框架的基础部分,提供IoC反转控制和依赖注入DI特性。 这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许从程序逻辑中分离出依赖关系和配置。
1、Core主要包含Spring框架基本的核心工具类,Spring的其他组件都要用到这个包里的类,Core模块是其他组件的基本核心。
2、Beans主要是BeanFacotry,它包含访问配置文件、创建和管理 bean 以及进行 Inversion of Control
| Dependency Injection ( IoC/DI )操作相关的所有类。
3、Context处理 BeanFactory,还是 ApplicationContext 的作用。模块构建于 Core 和 Beans 模块基础之上,提供了一种类似 JNDI 注册器的框架式的对象访问方法。 Context 模块继承了 Beans 的特性,为 Spring 核心提供了大量扩展,添加了对国际化(例如资源绑定)、 事件传播、资源加载和对Context 的透明创 建的支持。Context 模块同时也支持 J2EE 的一些特性, ApplicationContext 接口是Context 模块的关键。本质区别:(使用 BeanFacotry 的 bean 是延时加载的,ApplicationContext 是非延时加载的)
4、Expression Language模块提供了强大的表达式语言,用于在运行时查询和操纵对象。它是 JSP 2.1
规范中定义的 unifed expression language 的扩展。该语言支持设置/获取属性的值,属性的分配,方法的调用,访问数组上下文( accessiong the context of arrays )、容器和索引器、逻辑和算术运算符、命名变量以及从 Spring 的 IoC 容器中根据名称检索对象。它也支持 list 投影、选择和一般的 list 聚合
Spring AOP
- AOP 组件:提供面向切面编程实现,比如日志记录、权限控制等通用功能和业务逻辑分离技术。降低业务逻辑和通用功能的耦合。
- Aspects 组件:提供 AspectJ 的集成,是一个功能强大且成熟的 AOP 框架。
Spring Data Access/Integration数据访问和持久化框架的集成。
1、JDBC模块提供了一个 JDBC 抽象层,它可以消除冗长的 JDBC 编码和解析数据库厂商特有的错误代码。这个模块包含了 Spring 对 JDBC 数据访问进行封装的所有类。
2、ORM模块为流行的对象-关系映射 API,如 JPA、JDO、Hibernate、iBatis 等,提供了一个交互层。利用 ORM 封装包,可以混合使用所有 Spring 提供的特性进行 O/R 映射,如简单声明性事务管理。
3、OXM 模块提供了一个对 Object/XML 映射实现的抽象层,将 java 对象映射成 XML 数据,或者将XML 数据映射成 java 对象,Object/XML 映射实现包括 JAXB、Castor、XMLBeans、JiBX 和XStrearn。
4、JMS ( Java Messaging Service )模块提供一套 “消息生产者、消息消费者”模板用于更加简单的使用JMS,JMS 用于两个应用程序之间,或分布式系统中发送消息,进行异步通信。
5、Transaction支持编程和声明性的事务管理,这些事务类必须实现特定的接口,并且对所有的 POJO都适用
Spring Web
Spring Web模块提供了基础的面向 Web 的集成特性。例如,多文件上传、使用 servlet listeners 初始化
IoC 容器以及一个面向 Web 的应用上下文。它还包含 Spring 远程支持 Web 的相关部分。
Spring Aop针对AOP编程提供支持。1、Aspects模块提供了对 AspectJ 的集成支持。2、Instrumentation 模块提供了 class instrumentation 支持和 classloader 实现,使得可以在特定的应用服务器上使用。
Test
Test 模块支持使用 JUnit 和 TestNG 对 Spring 组件进行测试。
Instrumentation和Messaging
- 植入Instrumentation 组件:提供类工具的支持和类加载器的实现。
- messaging 组件:提供对消息传递体系结构和协议的支持。
Spring的全方位应用程序框架
Spring IoC/DI
IoC又叫依赖注入DI。它描述了对象的定义和依赖的一个过程,也就是说,依赖的对象通过构造参数、工厂方法参数或者属性注入,当对象实例化后依赖的对象才被创建,当创建bean后容器注入这些依赖对象。这个过程基本上是反向的,因此命名为控制反转IoC,它通过直接使用构造类来控制实例化,或者定义它们之间的依赖关系,或者类似于服务定位模式的一种机制。
- org.springframework.beans 和org.springframework.context 是Spring框架中IoC容器的基础
- BeanFactory 接口提供一种高级的配置机制能够管理任何类型的对象
- ApplicationContext 是 BeanFactory 的子接口。它能更容易集成Spring的AOP功能、消息资源处理(比如在国际化中使用)、事件发布和特定的上下文应用层比如在网站应用中的WebApplicationContext。
总之, BeanFactory 提供了配置框架和基本方法,ApplicationContext 添加更多的企业特定的功能。ApplicationContext 是 BeanFactory 的一个子接口,通过解析BeanFactory的源码是了解Spring的IoC容器的一个最佳选择
在Spring中,由Spring IoC容器管理的对象叫做beans。 bean就是由Spring IoC容器实例化、组装和以其他方式管理的对象。此外bean只是你应用中许多对象中的一个。Beans以及他们之间的依赖关系是通过容器配置元数据反映出来。
IoC/DI结构
核心容器由以下模块组成,spring-core, spring-beans,spring-context,spring-context-support和
spring-expression(Spring表达式语言)。
- spring-core和spring-beans模块提供了框架的基础功能,包括IOC和依赖注入功能。 BeanFactory是一个成熟的工厂模式的实现。你不再需要编程去实现单例模式,允许你把依赖关系的配置和描述从程序逻辑中解耦。
- 上下文(spring-context)模块建立在由Core和Beans模块提供的坚实的基础上:它提供一个框架式的对象访问方式,类似于一个JNDI注册表。上下文模块从Beans模块继承其功能,并添加支持国际化(使用,例如,资源集合),事件传播,资源负载,并且透明创建上下文,例如,Servlet容器。Context模块还支持Java EE的功能,如EJB,JMX和基本的远程处理。ApplicationContext接口是Context模块的焦点。spring-context-support支持整合普通第三方库到Spring应用程序上下文,特别是用于高速缓存ehcache,Cache)和调度(CommonJ,Quartz)的支持。
- spring-expression模块提供了强大的表达式语言去支持查询和操作运行时对象图。这是对JSP 2.1规范中规定的统一表达式语言(unified EL)的扩展。该语言支持设置和获取属性值,属性分配,方法调用,访问数组,集合和索引器的内容,逻辑和算术运算,变量命名以及从Spring的IoC容器中以名称检索对象。 它还支持列表投影和选择以及常见的列表聚合。
IoC和DI
某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转IoC
创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入DI
applicationContext & BeanFactory区别
BeanFactory接口
- spring的原始接口,针对原始接口的实现类功能较为单一,只用于内存敏感的受限环境开发中
- BeanFactory接口实现类的容器,特点是每次在获得对象时才会创建对象
ApplicationContext接口
- 每次容器启动时就会创建容器中配置的所有对象
- ApplicationContext在BeanFactory功能的基础之上提供了额外的对企业级开发的额外功能。例如提供国际化的消息访问、资源访问,可以进行事件传播
- 从类路径下加载配置文件: ClassPathXmlApplicationContext
- 从硬盘的绝对路径下加载配置文件:FileSystemXmlApplication
BeanFactory用于内存敏感的受限环境开发,而一般情况下多采用ApplicationContext
BeanFactory中的常见方法
- getBean(“受管bean的名称”):Object
- getBean(类型名.class):获取到指定类型的受管bean
- getBean(“受管bean的名称”,类型.class):类型 这里不是按类型查找,如果指定名称的bean不存在则NoSuchBeanDefinitionException;如果获取到的受管bean不是指定类型的对象则BeanNotOfRequiredTypeException