一、Spring框架概述
Spring是一个非常活跃的开源框架, 它是一个基于IOC和AOP来构架多层JavaEE系统的框架,它的主要目地是简化企业开发。
Spring以一种非侵入式的方式来管理你的代码, Spring提倡“最少侵入”,这也就意味着你可以适当的时候安装或卸载Spring。
Spring采用独立的模块式开发,这样可以有选择的使用其中的模块,降低了业务对象的复杂性和组件之间的耦合性。
Spring的AOP支持允许将一些通用的功能,如:性能分析,事务管理,日志记录等进行集中的模块处理,提高了复用,降低了和业务功能的耦合。
Spring支持和ORM层以及MVC层框架的整合,简化了对其他层次的访问。
Spring给开发者带来的好处:降低组件之间的耦合度,实现软件各层之间的解耦
不用关心事务API就可以执行数据库事务;
不用关心远程API就可以使用远程操作;
不用关心JMX API就可以进行管理操作;
不用关心JMS API就可以进行消息处理。
①JMX,Java Management eXtension,Java管理扩展,是一个为应用程序、设备、系统等植入管理功能的框架。JMX可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。
②JMS,Java Message Service,Java消息服务,是Java平台上有关面向消息中间件(MOM)的技术规范,它便于消息系统中的Java应用程序进行消息交换,并且通过提供标准的产生、发送、接收消息的接口简化企业应用的开发。
下载
Spring官网: http://spring.io
下载地址: http://repo.springsource.org/libs-release-local/org/springframework/spring/
1.1、Spring框架的特征和功能
轻量:从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
控制反转Ioc:Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
面向切面Aop:Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
容器:Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
框架:Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
MVC:Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架,Spring MVC是一个非常受欢迎的轻量级Web框架。
所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
1.2、Spring的组成
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
BeanFactory
,它是工厂模式的实现。BeanFactory
使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。Spring 框架的功能可以用在任何 J2EE 服务器中,大多数功能也适用于不受管理的环境。Spring 的核心要点是:支持不绑定到特定 J2EE 服务的可重用业务和数据访问对象。毫无疑问,这样的对象可以在不同 J2EE 环境 (Web 或 EJB)、独立应用程序、测试环境之间重用。
1.3、Spring Boot与Spring Cloud
Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务,Spring Cloud是一个基于Spring Boot实现的云应用开发工具;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。
二、IOC简介
IOC(Inversion of Control,即控制反转),是一种设计思想,IOC其实就是包含并管理应用对象的配置和生命周期,你可以配置你的每个bean如何被创建,也可以配置每个bean是只有一个实例,还是每次需要时都生成一个新的实例,以及它们是如何相互关联的。
DI(Dependency injection,即依赖注入)是IOC的一种常见的方式,是指应用在运行期,由外部容器(Spring容器)动态地将依赖对象注入到另一个对象中。
IOC的思想最核心的地方在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处:
第一,资源集中管理,实现资源的可配置和易管理。
第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。
IOC是Spring框架的核心内容,使用多种方式完美的实现了IOC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
以上部分内容借鉴于博客:https://www.cnblogs.com/best/p/5727935.html#_label3
补充:
BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等
ApplicationContext:通过API文档可以知道,ApplicationContext是BeanFactory的子接口。大部分程序都不会使用BeanFactory作为容器接口(通常JavaSE应用或者手机应用使用),而是使用ApplicationContext作为Spring的容器接口,它增强了BeanFactory的功能。
ApplicationContext的实现有四种方式:
FileSystemXmlApplicationContext:加载配置文件的时候采用的是项目的路径。
ClassPathXmlApplicationContext:加载配置文件的时候根据ClassPath位置。
XmlWebApplicationContext:在Web环境下初始化监听器的时候会加载该类。
AnnotationConfigApplicationContext:根据注解的方式启动Spring 容器。
从上下文中获取Bean的常用方法有:
Object getBean(String name);//通过id的名称获取,需要强制转换
T getBean(Class
T getBean(String name, Class
1.使用XML方式配置IOC
beans其他常用属性:
(1)default-lazy-init:指定该beans元素下配置的所有的bean都默认延迟初始化(没有使用到不进行实例化);
(2)default-autowire:指定该beans下配置的所有的bean默认是自动装配的;
(3)default-init-method:指定该beans下配置的所有的bean默认的初始方法;
(4)default-destroy-method:指定beans元素下配置的所有的bean默认的回收方法。
注意:在beans下配置的属性是全局属性,在每个bean元素下也是可以单独指定的,只是要把default去掉即可(default-autowire对应为autowire)。bean中指定的属性只能在当前的bean元素上起作用,当二者出现冲突的时候会优先使用bean下指定的属性。
bean的其他常用属性:
(1)abstract以及parent: abstract以及parent是搭配使用的,如果bean定义了属性abstact=true,那么这个类就无法通过Spring容器拿到,而是作为一个模板存在。有点类似于设计模式中的模板方法。这个bean对应的类它定义的属性,方法可以被复用。通过Parent属性在子类中可以指向被abstract定义的bean。
(2)singleton(默认为“true”):定义Bean是否是Singleton(单例)。如果设为“true”,则在BeanFactory作用范围内,只维护此Bean的一个实例。如果设为“flase”,Bean将是Prototype(原型)状态,BeanFactory将为每次Bean请求创建一个新的Bean实例。
(3)lazy-init(默认为“default”):用来定义这个Bean是否实现延迟初始化。如果为“true”,它将在BeanFactory启动时初始化所有的SingletonBean。反之,如果为“false”,它只在Bean请求时才开始创建SingletonBean。
(4)autowire(自动装配,默认为“default”):它定义了Bean的自动装载方式。
1、“no”:不使用自动装配功能。
2、“byName”:通过Bean的属性名实现自动装配。
3、“byType”:通过Bean的类型实现自动装配。
4、“constructor”:类似于byType,但它是用于构造函数的参数的自动组装。
5、“autodetect”:通过Bean类的反省机制(introspection)决定是使用constructor还是byType方式进行自动装配。
(5)depends-on(依赖对象):这个Bean在初始化时依赖的对象,这个对象会在这个Bean初始化之前创建。
(6)init-method:用来定义Bean的初始化方法,它会在Bean组装之后调用。它必须是一个无参数的方法。
init-method在Bean的属性被初始化之后执行,一般做初始化数据
(7)destroy-method:用来定义Bean的销毁方法,它在BeanFactory关闭时调用。同样,它也必须是一个无参数的方法。它只能应用于singletonBean。
destroy-method在Bean被销毁之前进行执行,一般作为清理资源
Bean的生命周期如下:
(8)factory-method:定义创建该Bean对象的工厂方法。它用于下面的“factory-bean”,表示这个Bean是通过工厂方法创建。此时,“class”属性失效。
(9)factory-bean:定义创建该Bean对象的工厂类。如果使用了“factory-bean”则“class”属性失效。
(10)scope,用来指定该bean的作用域,其值有:
1、singleton: 在这个spring容器里面只有一个实例;
2、prototype: 每一次请求都会创建一个新的bean实例;
3、request: 每一次请求创建一个新的实例,在Web Application中有效;
4、session: 每一个session创建一个新的实例,在Web Application中有效;
5、global-session: 对每一个global HTTP session创建一个新的实例,在Web Application中有效。
作用域中比较常用的是singleton和prototype,没有配置作用域的情况下Bean的默认作用域是singleton的。Spring容器对于singleton和prototype进行管理是不一样的。如果Bean是singleton的时候Spring的容器会进行跟踪Bean实例的状态,负责维护Bean实例的生命周期的行为;如果Bean被设置为prototype作用域时,Spring容器仅仅只是调用构造函数进行创建一个实例,一旦创建成功容器就不再进行跟踪实例,也不会维护Bean实例的状态。
单例的在系统中进行只需要创建一次就能重复的使用,会减少系统在创建实例和回收实例时的资源开销。
依赖注入的两种方式:
(1).设值注入:
需要在对应的实体类中有相应的Setter方法
(2).构造注入:
需要在对应的实体类中有相应的构造函数
使用List、Set、Map:
1
自动绑定:
也可以直接在某个bean中单独设置,如:
2.基于Annotation的注解方式:
常用的注解:
(1)@Component:用来标注任何一个普通的Java类;如:
@Component
public class Employee {
...
}
(2)@Controller:用来标注一个控制类(Struts的Action或者Springwebmvc的Controller); 如:
@Controller
public class LoginServlet {
...
}
(3)@Service:用来标注一个业务逻辑的Java类;如:
@Service
public class EmployeeServiceImpl implements IEmployeeService {
...
}
(4)@Repository:标注一个DAO的Java类; 如:
@Repository
public class EmployeeDaoImpl implements IEmployeeDao {
...
}
(5)@AutoWired: 表示告诉Spring ,这里是 一个属性,自动注入;如:
@Service
public class EmployeeServiceImpl implements IEmployeeService {
@Autowired
private IEmployeeDao employeeDao;
...
}
补充:@Autowired(required=false):表示忽略当前要注入的bean,若有直接注入,若没有则跳过(此时也不会报错)。
@Autowired注入规则
@Autowired默认是按照byType进行注入的,但是当byType方式找到了多个符合的bean,又是怎么处理的?Autowired默认先按byType,如果发现找到多个bean,则又按照byName方式比对,如果还有多个,则报出异常。
例子:
@Autowired
private Car redCar;
1. spring先找类型为Car的bean
2. 如果存在且唯一,则OK;
3. 如果不唯一,在结果集里,寻找name为redCar的bean。因为bean的name有唯一性,所以,到这里应该能确定是否存在满足要求的bean了
@Autowired也可以手动指定按照byName方式注入,使用@Qualifier标签,例如:
@Autowired()
@Qualifier("baseDao" )
因为bean的name具有唯一性,理论上是byName会快一点,但spring默认使用byType的方式注入。另外补充一点:@Resource(这个注解属于J2EE的)的标签,默认是按照byName方式注入的。
(6) @Resource: 依赖资源,依赖对象,不是Spring的注解;如:
@Repository("employeeDaoImpl_Test")
public class EmployeeDaoImpl implements IEmployeeDao {
...
}
@Service
public class EmployeeServiceImpl implements IEmployeeService {
//@Autowired
@Resource(name="employeeDaoImpl_Test")
private IEmployeeDao employeeDao;
...
}
(7)@Value : 属性值 的注入,如:
@Component
public class Employee {
private int empId;
@Value("张三")
private String empName;
@Value("20")
private int age;
...
}
当上面的注解配置完成之后,可以方式一:在XML配置文件中自动扫描和绑定,如:
方式二:基于注解的零xml配置:
(8)@Configuration: 用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取容器时需要使用,使用@Configuration注解表示这个一个配置类,等同于xml配置中xml文件。
(9)@ComponentScan:用于指定spring在初始化容器时要扫描的包。
基于注解的零XML配置示例:
//使用@Configuration注解表示这个一个配置类,等同于xml配置中xml文件。
@Configuration
//类似xml配置中的component-scan,我们可以配置针对特别package的扫描配置,自动将包内@Component、@Service 等注解的bean类给扫描出来,注入到容器中。用法如下:
@ComponentScan(basePackages = "com.springstudy")
public class SpringConfiguration {
}
public class SpringTest {
private static ApplicationContext ac;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
if(ac==null) {
//在纯java类配置的场景中,AnnotationConfigApplicationContext承担了同样地构建容器实例的角色
ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
}
}
@Test
public void test() {
IEmployeeService empService = ac.getBean("employeeServiceImpl",EmployeeServiceImpl.class);
Employee emp = empService.getEmployee();
System.out.println(emp);
}
}
其他常用的注解:
(10)@Bean:该注解只能写在方法上,将方法的返回值作为一个bean,并且放入spring容器。
其属性name:可以给当前@Bean注解方法创建的对象指定一个名称。
@Bean(name = {"jdbcTemplate"})
public JdbcTemplate createJdbcTemplate(@Qualifier(value = "dataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
(11)@PropertySource:用于加载.properties文件中的配置。如:
@PropertySource(value = {"classpath:jdbc.properties"})
public class JdbcConfig {
@Value(value = "${jdbc.driverClass}")
private String driverClassName;
@Value(value = "${jdbc.url}")
private String url;
@Value(value = "${jdbc.username}")
private String username;
@Value(value = "${jdbc.password}")
private String password;
@Bean(name = {"jdbcTemplate"})
public JdbcTemplate createJdbcTemplate(@Qualifier(value = "dataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean(name = {"dataSource"})
public DataSource createDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
(12)@Import:用于导入其他配置类。
@Configuration
@ComponentScan(value = {"com.springstudy"})
@Import(value = JdbcConfig.class)
public class SpringConfiguration {
}