Spring简介
-
Spring是一种开源轻量级框架,是为了解决企业应用程序开发复杂性而创建的,Spring致力于解决Java EE的各层解决方案,而不仅仅于某一层的方案。
-
可以说Spring是企业应用开发的“一站式”选择,Spring贯穿于表现层、业务层、持久层,然而Spring并不想取代那些已经有的框架,而是以高度的开放性,与这些已有的框架进行整合。
-
Spring是一个全面的解决方案,它坚持一个原则:不重新造轮子。已经有较好解决方案的领域,Spring绝不重复性实现,比如:对象持久化和OR映射,Spring只对现有的
JDBC
,Hibernate
等技术提供支持,使之更容易使用,而不做重复的实现。Spring框架有很多特性,这些特性由7个定义良好的模块构成:Spring Core
:即,Spring核心,它是框架最基础的部分,提供IOC
和依赖注入特性。Spring Context
:即,Spring上下文容器,它是BeanFactory
功能加强的一个子接口。Spring Web
:它提供Web
应用开发的支持。Spring MVC
:它针对Web
应用中MVC
思想的实现。Spring DAO
:提供对JDBC
抽象层,简化了JDBC
编码,同时,编码更具有健壮性。Spring ORM
:它支持用于流行的ORM
框架的整合,比如:Spring
+Hibernate
、Spring
+iBatis
、Spring
+JDO
的整合等等。Spring AOP
:AOP
即,面向切面编程,它提供了与AOP
联盟兼容的编程实现。
-
Spring常用组件:
xml配置与@Configuration
注解配置
-
xml配置方式:
beans.xml
主要代码如下:<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="..." ...> <!-- Person类定义在此省略 --> <bean id ="person" class="com.study.spring.Person"> <property name="name" value="yhl"></property> <property name="age" value="18"></property> </bean> </beans>
测试类主要代码如下:
public class MainTest1{ public static void main(String args[]){ // 把beans.xml中的类加载到容器中 ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); // 从容器中获取bean Person person = (Person) app.getBean("person"); System.out.println(person); } }
-
注解配置方式:
配置类主要代码如下:
// 配置类,相当于配置文件 @Configuration public class MainConfig{ // 给容器中注册一个bean,类型为返回值的类型 @Bean public Person person(){ return new Person("yhl",19); } }
测试类主要代码如下:
public class MainTest2{ public static void main(String args[]){ ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class); // 从容器中获取bean Person person = (Person) app.getBean("person"); System.out.println(person); } }
-
@Configuration
与beans.xml
作用一样,@Configuration
更简单、灵活
@ComponentScan
扫描规则
-
可以定制包扫描时的过滤规则,比如,以下代码会扫描出
@Controller
和BookService
:@Configuration @ComponentScan(value="com.study.spring",includeFilters={ @Filter(type=FilterType.ANNOTATION,classes={Controller.class}), @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}) },useDefaultFilters=false) public class MainConfig2 { // 给容器中注册一个bean,类型为返回值的类型 @Bean public Person person01(){ return new Person("yhl",19); } }
-
@ComponentScan
注解的属性:value
:指定要扫描的包。excludeFilters = Filter[]
:指定扫描的时候按照什么规则排除哪些组件。includeFilters = Filter[]
:指定扫描的时候只需要包含哪些组件。useDefaultFilters = false
:默认是true扫描所有组件,要改成false,才能使用自定义扫描范围。
-
@Filter
的扫描规则如下:FilterType.ANNOTATION
:按照注解,比如@Controller
、@Service
、@Repository
、@Component
注解。FilterType.ASSIGNABLE_TYPE
:按照给定的类型,比如BookService
类型。FilterType.ASPECTJ
:使用ASPECTJ
表达式。FilterType.REGEX
:使用正则指定。FilterType.CUSTOM
:使用自定义规则,自已写类,实现TypeFilter
接口。
-
自定义规则示例:
public class YhlTypeFilter implements TypeFilter{ private ClassMetadata classMetadata; /* * MetadataReader:读取到当前正在扫描类的信息 * MetadataReaderFactory:可以获取到其他任何类的信息 */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException{ // 获取当前类注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); // 获取当前正在扫描的类信息 classMetadata = metadataReader.getClassMetadata(); // 获取当前类资源(类的路径) Resource resource = meatadataReader.getResource(); String className = classMetadata.getClassName(); System.out.println("--->" + className); // 当类包含er字符,则匹配成功,返回true if(className.contains("er")){ return true; } return false; } }
@Configuration @ComponentScan(value="com.study.spring",includeFilters={ @Filter(type=FilterType.CUSTOM,classes={YhlTypeFilter.class}) },useDefaultFilters=false) public class MainConfig2 { // 给容器中注册一个bean,类型为返回值的类型 @Bean public Person person(){ return new Person("yhl",19); } }
@Scope
扫描规则
-
@Scope
注解的值:prototype
:多实例,IOC
容器启动的时候并不会取调用方法创建对象,而是每次获取的时候才会调用方法创建对象。singleton
:单实例(默认),IOC容器启动的时候会调用方法创建对象并放到IOC
容器中,以后每次获取的就是直接从容器中拿的同一个bean
。request
:主要针对web
应用,递交一次请求创建一个实例。session
:同一个session
创建一个实例。
-
没加
@Scope
之前, 默认的bean
是单实例的。 -
比如,以下代码指定
bean
为多实例:@Configuration public class MainConfig3{ // 给容器中注册一个bean,类型为返回值的类型,默认是单实例 @Scope("prototype") @Bean public Person person(){ return new Person("yhl",19); } }
@Lazy
懒加载
-
主要针对单实例
bean
(单实例bean
默认在容器启动的时候创建对象),使用懒加载后,容器启动的时候不创建对象,仅当第一次使用(获取)bean
的时候才创建并初始化。 -
示例如下:
@Configuration public class MainConfig4{ // 给容器中注册一个bean,类型为返回值的类型,默认是单实例 @Lazy @Bean public Person person(){ return new Person("yhl",19); } }
@Conditional
条件注册bean
-
当引入
@Conditional
时, 容器可以选择性的注册bean
。比如,当操作系统为WINDOWS
时,注册yhl1
实例; 当操作系统为LINUX
时, 注册yhl2
实例:// 配置类 @Configuration public class MainConfig5{ @Conditional({WinCondition.class}) @Bean("yhl1") public Person yhl1(){ return new Person("yhl1",19); } @Conditional({LinuxCondition.class}) @Bean("yhl2") public Person yhl2(){ return new Person("yhl2",20); } }
// 条件类,必须得实现Spring提供的Confition接口 public class WinCondition implements Condition{ /* * ConditionContext: 判断条件能使用的上下文(环境) * AnnotatedTypeMetadata: 注释信息 */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 能获取到IOC容器正在使用的beanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 获取当前环境变量(包括操作系统时WIN还是LINUX) Environment environment = context.getEnvironment(); String os_name = environment.getProperty("os.name"); if(os_name.contains("Windows")){ return true; } return false; } }
// 条件类,必须得实现Spring提供的Confition接口 public class LinCondition implements Condition{ /* * ConditionContext: 判断条件能使用的上下文(环境) * AnnotatedTypeMetadata: 注释信息 */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 能获取到IOC容器正在使用的beanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 获取当前环境变量(包括操作系统时WIN还是LINUX) Environment environment = context.getEnvironment(); String os_name = environment.getProperty("os.name"); if(os_name.contains("linux")){ return true; } return false; } }
-
FactoryBean
与BeanFactory
的区别:可以把Java
实例bean
通过FactoryBean
注入到容器中;BeanFactory
从容器中获取实例化后的bean
。
@Import
注册bean
-
给容器注册组件的方式:
@Bean
:导入第三方的类或包的组件,比如Person
为第三方的类,需要在IOC
容器中使用。- 包扫描+组件的标注注解(
@ComponentScan
:@Controller
、@Service
、@Repository
、@Component
):一般是针对自己写的类,使用这个。 @Import
:快速给容器导入一个组件。@Bean
有点简单。- @Import(要导入到容器中的组件):容器会自动注册这个组件,
bean
的id
为全类名 - ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
- ImportBeanDefinitionRegistrar:可以手动添加组件到
IOC
容器,所有bean
的注册可以使用BeanDefinitionRegistry
,写YhlImportBeanDefinitionRegistrar
实现ImportBeanDefinitionRegistrar
接口即可
- @Import(要导入到容器中的组件):容器会自动注册这个组件,
- 使用
Spring
提供的FactoryBean
(工厂Bean
)进行注册:容器调用getObject()
返回对象,把对象放到容器中;getObjectType()
返回对象类型;isSingleton()
是否单例进行控制。新建YhlFactoryBean
实现FactoryBean
,在config
里新建yhlFactoryBean()
方法。
-
使用
@Import
将dog
、cat
的bean
注册到容器中:@Configuration // 导入组件,ID默认是组件的全类名 @Import(value = {Dog.class,Cat.class}) public class MainConfig6 { // 容器启动时初始化person的bean实例 @Bean public Person person(){ return new Person("yhl",19); } }
-
ImportSelector
可以批量导入组件的全类名数组,自定义逻辑返回需要导入的组件:public class YhlImportSelector implements ImportSelector{ @Override public String[] selectImports(AnnotationMetadata importingClassMetadata){ // 返回全类名的bean return new String[]{"com.study.spring.Fish","com.study.spring.Tiger"}; } }
@Configuration @Import(value = {Dog.class,Cat.class,YhlImportSelector.class}) public class MainConfig7 { // 容器启动时初始化person的bean实例 @Bean public Person person(){ return new Person("yhl",19); } }
-
通过
ImportBeanDefinitionRegistrar
自定义注册,向容器中注册bean
:public class YhlImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /* * AnnotationMetadata:当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类,把所有需要添加到容器中的bean加入 * 调用BeanDefinitionRegistry.registerBeanDefinition自定义手工注册进来 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean bean1 = registry.containsBeanDefinition("com.study.spring.Dog"); boolean bean2 = registry.containsBeanDefinition("com.study.spring.Cat"); // 如果Dog和Cat同时存在于IOC容器中,那么创建Pig类,加入到容器 if(bean1 && bean2){ // 以前的bean都是全类名,现在自定义bean名 // 对于要注册的bean,需要给bean进行封装 RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class); // 注册一个bean,bean名为pig registry.registerBeanDefinition("pig", beanDefinition); } } }
@Configuration @Import(value = {Dog.class,Cat.class,YhlImportSelector.class,YhlImportBeanDefinitionRegistrar.class}) public class MainConfig8 { // 容器启动时初始化person的bean实例 @Bean public Person person(){ return new Person("yhl",19); } }
-
通过实现
FactoryBean
接口方式来加载bean
:public class YhlFactoryBean implements FactoryBean<Monkey>{ @Override public Monkey getObject() throws Exception { return new Monkey(); } @Override public Class<?> getObjectType() { return Monkey.class; } @Override public boolean isSingleton() { return true; } }
@Configuration public class MainConfig9 { @Bean public YhlFactoryBean yhlFactoryBean(){ return new YhlFactoryBean(); } }
默认获取到的是工厂
bean
调用getObject
创建的对象,要获取工厂bean
本身,需要在id
前加个yhlFactoryBean
。
bean生命周期
-
bean
的生命周期是指**bean
创建-----初始化----销毁**的过程,是由容器进行管理的。 -
可以自定义
bean
初始化和销毁方法:容器在bean
进行到当前生命周期的时候, 来调用自定义的初始化和销毁方法,有3种方式:-
指定初始化和销毁方法:
-
在
beans.xml中
可以指定init-method
和destory-mothod
。 -
用注释的话,在配置类里通过
@Bean(initMethod="init",destroyMethod="destroy")
指定。@Bean(initMethod="init", destroyMethod="destory") public Bike bike(){ return new Bike(); }
单实例:当容器关闭的时候,会调用
destroy
消耗。多实例:容器只负责初始化,但不会管理bean,容器关闭不会调用销毁方法。
-
-
让
Bean
实现InitializingBean
和DisposableBean
接口:InitializingBean
(定义初始化逻辑):afterPropertiesSet()
方法:当beanFactory
创建好对象,且把bean
所有属性设置好之后,会调这个方法,相当于初始化方法。DisposableBean
(定义销毁逻辑):destory()
方法,当bean
销毁时,会把单实例bean
进行销毁。
@Component public class Train implements InitializingBean, DisposableBean{ public Train(){ System.out.println("Train......constructor............"); } // 当bean销毁时,调用此方法 @Override public void destroy() throws Exception { System.out.println("Train......destory......"); //logger.error } // 当bean属性赋值和初始化完成时调用 @Override public void afterPropertiesSet() throws Exception { System.out.println("Train.......afterPropertiesSet()..."); } }
-
使用
JSR250
规则定义的(java规范)两个注解来实现:@PostConstruct
:在bean
创建完成,且赋值完成后进行初始化,属于JDK规范的注解。@PreDestroy
:在bean
将被移除之前进行通知,在容器销毁之前进行清理工作。
@Component public class Jeep { public Jeep(){ System.out.println("Jeep.....constructor........"); } @PostConstruct public void init(){ System.out.println("Jeep.....@PostConstruct........"); } @PreDestroy public void destory(){ System.out.println("Jeep.....@PreDestroy......"); } }
-
-
BeanPostProcessor
类(interface)是bean
的后置处理器,负责在初始化方法前后进行一些处理工作:postProcessBeforeInitialization()
:在初始化之前进行后置处理工作(在init-method
之前)。在任何初始化方法调用之前调用此方法(比如在InitializingBean
的afterPropertiesSet
初始化之前,或自定义init-method
调用之前使用)。postProcessAfterInitialization()
:在初始化之后进行后置处理工作,比如在InitializingBean
的afterPropertiesSet()
之后。
/* * 后置处理器:初始化前后进行处理工作 * 将后置处理器加入到容器中 */ @Component public class YhlBeanPostProcessor implements BeanPostProcessor{ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization...."+beanName+"..."+bean); // 返回一个对象(传过来的对象),也可包装好再返回 return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization...."+beanName+"..."+bean); return bean; } }