培训出身,非科班,全凭自己浓厚的兴趣成为一名java软件开发工程师,毕业后工作两年,自以为springmvc springboot等玩的很6了,前阵子面试后才让我知道,需要看书了。不然看到的时候懂,问到的时候不懂。记得面试官问了一个很搞笑的问题,http的2x 3x 4x 5x是代表什么意思?嗯,我懵逼了。最后我才忍不住问了,才知道其实就是请求状态码 200 400.......好了 废话不多说了。
本章内容:
spring的bean容器
介绍spring的核心模块
更为强大的spring生态系统
spring的新功能
1.1 spring的bean容器
spring最根本的使命:简化java开发
为了降低java开发的复杂性,spring采取了一下四种关键策略:
-
基于POJO的轻量级和最小侵入性编程
-
通过依赖注入和面向接口实现松耦合
-
基于切面和惯例进行声明式编程
-
通过切面和模板减少样板式代码
开发过程中经常会遇到POJO和javabean这两个词,书上提到,POJO:一个简单普通的java类。但二者到底什么区别?很多人一知半解。
以下解释来自:
POJO 就好比是一个普通自行车,而 JavaBean 就好比是一个电动自行车(特殊的自行车)。普通自行车拥有轮子,而电动自行车也有轮子,但是电动自行车有了电瓶,才能称为是电动自行车。它俩的区别就在于本质上的不同,一个带电瓶,一个不带电瓶,虽然它俩都可以表示为自行车,但因为本质上的不同,带电的能称为是电动自行车,而不带电的只能称为普通自行车。在 Java 中,POJO 是一个普通的 Java对象,而 JavaBean 却是一个特殊的 Java对象,这个特殊的 Java对象具有一定的标准才能称为 JavaBean。也就是说,万物皆对象,即POJO,其中,满足特殊条件和规范的就成为javabean。下面我们就结合 Java 近距离看 POJO 与 JavaBean。
POJO 是 Plain Ordinary Java Object 的缩写,意思是 简单普通的 Java对象,它的特征是:
1、拥有一些 private修饰的属性;
2、这些 private修饰的属性都提供 get…()&set…() 方法。
我们把这样的类称为 POJO类,POJO类 实例化出来的对象称为 POJO对象。下面是一个 POJO类的例子:
// 自行车
public class Bike {
private String wheel; // 轮子
// set...() & get...()
public String getWheel() {
return wheel;
}
public void setWheel(String wheel) {
this.wheel = wheel;
}
}
JavaBean 从字面上来看,它有咖啡豆的含义,关于 Java 这个名字由来的故事相信大家都听说过,它的名字是和印度尼西亚爪哇岛上爪哇咖啡有关,在 Java中也有很多类和方法的名字都和咖啡有着密不可分的联系,就连 JavaBean 也有咖啡豆的含义,寓意着它是 Java中重要的组成部分,它也必须符合一些特定的标准才可称为 JavaBean,它的特征是:
1、所有的属性都被 private修饰;
2、这个类必须有一个无参构造器;
3、所有的属性必须都提供 get…()&set…() 方法;
4、这个类必须是可序列化的,实现 serializable 接口。
我们把符合这样特征的类称为 JavaBean类,JavaBean类 实例化出来的对象称为 JavaBean对象。下面是一个 JavaBean类的例子:
// 电动车
public class Ebike implements serializable {
private String wheel; // 轮子
// 无参构造器
public Ebike() {}
// set...() & get...()
public String getWheel() {
return wheel;
}
public void setWheel(String wheel) {
this.wheel = wheel;
}
}
这个时候,序列化这个词相信很多人也很熟悉。具体什么作用?为什么要序列化?
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
更详细内容有兴趣的可以看这篇文章:Java基础学习总结——Java对象的序列化和反序列化
想要更深入了解的话就看这个:深入理解JAVA I/O系列五:对象序列化
稍微拓展了解了之后,好了,回归正题,这些java类---POJO形式上虽然看起来很简单,但spring一样可以让它赋予魔力,方式之一就是通过DI来装配它们。DI----依赖注入。通过DI,对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定。对象无需自行创建或管理它们的依赖关系。依赖关系将自动注入到需要它们的对象当中去。常用的方式就是构造器注入。将一个对象作为另外一个对象的构造器参数注入的方式。
创建应用组件之间协作的行为通常被称为装配(wiring)。spring有多种装配bean的方式,采用XML是很常见的。比如:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
<bean id="knight" class="com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest" />
</bean>
<bean id="quest" class="com.springinaction.knights.SlayDragonQuest">
<constructor-arg value="#{T(System).out} />
</bean>
</beans>
在这里,BraveKnight和SlayDragonQuest被声明为Spring中的bean。就BraveKnight bean来讲,它在构造时传入了对SlayDragonQuest bean的引用,将其作为构造器参数。同时,SlayDragonQuest bean的声明使用了Spring表达式语言(Spring Expression Language),将System.out(这是一个PrintStream)传入到了SlayDragonQuest的构造器中。
如果XML配置不符合你的喜好,spring还支持使用java来描述配置。
import com.springframework.content.annotation.Configuration;
@Configuration
public class KnightConfig{
@Bean
public Knight knight(){
return new BraveKnight(quest());
}
@Bean
public Quest quest(){
return new SlayDragonQuest(System.out);
}
}
spring通过应用上下文(Application Context)装载bean、的定义并把它们组装起来。Spring应用上下文全权负责对象的创建和组装。
==========================================================
DI能够让相互协作的软件组件保持松散耦合。而面向切面编程(AOP)可以把遍布应用各处的功能分离出来形成可重用的组件。
===========================================================
程序可以理解为一个圆,AOP就是在这个圆外围的同心圆,程序运行时从左到右穿过两个圆。要将一个类抽象为一个切面,可以在spring配置文件中声明它。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
<bean id="knight" class="com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest" />
</bean>
<bean id="quest" class="com.springinaction.knights.SlayDragonQuest">
<constructor-arg value="#{T(System).out} />
</bean>
<bean id="minstrel" class="com.springinaction.knights.Minstrel">
<constructor-arg value="#{T(System).out} />
</bean>
<aop:config>
<aop:aspect ref ="minstrel">
<aop:pointcut id="embard"> expression="execution(* *.embarkOnQuest(..))" />
<aop:before pointcut-ref="embark" method="singBeforeQuest" />
<aop:after pointcut-ref="embark" method="singBeforeQuest" />
</aop:aspect>
</aop:config>
</beans>
1.2 容纳你的bean
1.2.1使用应用上下文
- AnnotationConfigApplicationContext:从一个或多个基于java的配置类中加载Spring应用上下文
- AnnotaionConfigWebApplicationContext:从一个或多个基于java的配置类中加载Spring Web 应用上下文
- ClassPathXmlApplicationContext:从类路径下的一个或多个xml配置文件中加载上下文定义,把应用上下文的定义文件作为类资源
- FileSystemXmlApplicationContext:从文件系统下的一个或多个xml配置文件中加载上下文定义
- XmlWebApplicationContext:从web应用下的一个或多个xml配置文件中加载上下文定义
1)从文件系统加载xml文件
ApplicationContext context = new FileSystemXmlApplicationContext("knight.xml");
<!-- 如果需要从resources路径下加载,可以使用classpath -->
ApplicationContext context = new FileSytemXmlApplicationContext("classpath:knight.xml")
2)从类路径下加载
ApplicationContext context = new ClassPathXmlApplicationContext("knight.xml");
3)从java配置中加载
ApplicationContext context = new AnnotationConfigApplicationContext(com.xxx.knights.config.KnightConfig.class);
1.2.2 bean的生命周期
传统java应用中,使用java关键字new进行bean实例化,这个bean就可以使用了。一旦该bean不再被使用,则由java自动进行垃圾回收。
spring容器中的bean生命周期就复杂很多了,以下流程图来自:Spring Bean的生命周期(非常详细)
我觉得我只要大概知道有这么个流程就行了 不必深究。会用,知道大概什么原理,毕竟要学的东西很多,要跟上时代节奏不被淘汰的技术。(不知道这个想法对不对)
1.3俯瞰Spring风景线
1.3.1 Spring模块
六大模块划分如下:
模块分解分析:
1.Spring核心容器
容器 是Spring框架最核心的部分。管理着Spring应用中bean的创建、配置和管理。所有的Spring模块都建立在核心容器之上。
2.Spring的AOP模块
AOP可以帮助应用对象解耦,可以将遍布系统的关注点(例如事务和安全),从它们所应用的对象中解耦出来。
3.数据访问与集成
Sping的JDBC和DAO(Data Access Object)模块抽象了数据库连接等样板代码(重复性代码),使我们的数据库代码编程简单明了。还构建了语义丰富的异常层(会有sql报错信息)
喜欢ORM工具而不喜欢直接使用JDBC的开发者,Spring的ORM模块建立在对DAO的支持之上,Spring对流行的ORM框架进行了集成,包括Hibernate等。
本模块包含了JMS之上构建的Spring抽象层,使用消息以异步的方式与其他应用集成。
本模块会使用SpringAOP模块为Spring应用中的对象提供事务管理服务
4. Web与远程调用
MVC(Model-View-Controller)模式是一种普遍被接受的构建web应用的方法。java有很多MVC框架,如:struts,JSF等。但它的web和远程调用模块自带强大的MVC框架。
5. Instrumentation
Spring的instrumentation模块提供了为JVM添加代理(agent)的功能。这个模块使用场景非常有限,了解即可
6.测试
Spring提供了测试模块。
1.3.2 Spring Portfolio
Spring远不止Spring框架所下载的那些。整个Spring Portfolio几乎为每一个领域的Java开发都提供了Spring编程模型。
- Spring Web Flow
Spring Web Flow建立在SpringMVC框架上,它为基于流程的会话式Web应用(可以想象一些购物车或者向导功能)提供了支持。
- Spring Web Service
- Spring Security
利用SpringAOP,Spring Security为Spring应用提供了声明式的安全机制
- Spring Integration
- Spring Batch
当我们需要对数据进行大量操作时,没有任何技术可以比批处理更胜任这种场景。可以通过Spring Batch开发一个批处理应用
- Spring Data
springdata 使得在Spring中使用任何数据库都变得非常容易。。不管是使用文档数据库如:MongoDB,图数据库如:Neo4j,还是传统的关系型数据库,SpringData都为之提供了一种简单的编程模型。
- Spring Social
社交网络是互联网领域中新兴的一种潮流,越来越多的应用正在融入社交网络网站,如Facebook或者Twitter。如果你对此感兴趣,可以了解一下Spring Social,这是Spring的一个社交网络扩展模块。
- Spring mobile
Spring Mobile是Spring MVC新的扩展模块,用于支持移动Web应用开发。
- Spring For Android
- Spring Boot
Spring极大的简化了众多的编程任务,减少甚至少出了很多样板式代码。Springboot大量依赖于自动配置技术,她能消除大部分(很多场景中,甚至是全部)Spring配置。它还提供了多个Starter项目,不管你使用maven还是gradle,这都能减少Spring工程构建文件的大小!!!!!重点学习!!!
---------------------------------------------------------------------------
总结:
在本章,我们体验了Spring的DI。DI是组装应用对象的一种方式,借助这种方式对象无需知道依赖来自何处或者依赖的实现方式。不同于自己获取依赖对象,对象会在运行期赋予它们所依赖的对象。依赖对象通常会通过接口了解所注入的对象,这样的话就能确保低耦合。DI说白了,就是我们平时听的最多的依赖注入。再实际一点,Spring装配bean有三种方式:
==> 1. 自动化配置(最推荐,避免显示配置带来的维护成本)
1.1 组件扫描:spring自动发现容器所创建的bean。开启组件扫描,默认情况下自动扫描配置类相同包(以及子包)下所有带有@component注解的类,并为其自动创建一个bean。开启组件扫描有两种方式,基于java配置(推荐)和xml配置:
Java配置:在配置类上添加@componentScan注解
Xml配置:利用<context:component-scan base-package=”...”/>
1.2 自动装配:spring自动满足bean之间的依赖。使用@Autowired(推荐)或@Inject注解添加在构造、setter还是其他方法上,实现bean的自动注入,无需手动去new。
==> 2. Java配置(推荐,基于java语言,类型安全易于重构)
利用@Bean注解来声明(创建)一个bean,同时还可以注入另外依赖的bean(利用构造器和setter方法)
==> 3. Xml配置
3.1利用<bean>标签声明一个bean。
举例 <bean id = “peoson” class=”soundsystem.Person” />
3.2 如何注入bean(构造器和setter方法)
构造器注入bean,举例
<bean id = “cdPlayer” class= “com.CDPlayer” >
<constructor-arg ref=”cd” />
</bean>
构造器注入字面量,举例
<bean id = “...” class= “...”>
<constructor-arg value=”...” />
</bean>
c命名空间注入bean,举例
<bean id = “...” class= “...”c:cd-ref=”...” />
c命名空间注入字面量,举例
<bean id = “...” class= “...” c:_...=”...” />
利用<list>、<set>等标签,构造器注入方式可以用来装配集合,而c命名空间不行。
Setter方法注入bean,举例
<bean id = “cdPlayer” class= “com.CDPlayer” >
<property name = “...” ref = “...” />
</bean> 或者使用p命名空间
<bean id = “cdPlayer” class= “com.CDPlayer” p: cd-ref = “...” />
Setter方法注入字面量,举例
<bean id = “cdPlayer” class= “com.CDPlayer” >
<property name = “...” value = “...” />
</bean> 或者使用p命名空间
<bean id = “cdPlayer” class= “com.CDPlayer” p: ... = “...” />
除了DI,我们还介绍了Spring对AOP的支持。面向切面编程,其实就是能够避免重复性代码,在需要这些代码的时候切入到程序中,就像登录功能,有的地方需要登录,有的地方不需要登录,而需要登录的地方业务逻辑都是一样的,如果每个地方都写上相同的代码,维护起来相当麻烦,显然不可取。这也就是AOP的目的所在。
PS:工作忙,间断的写完了这篇笔记,若有不对的地方欢迎指正,我当虚心学习。