本文共 11609 字,大约阅读时间需要 38 分钟。
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常用组件:
@Configuration
注解配置xml配置方式:
beans.xml
主要代码如下:
测试类主要代码如下:
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); }}
注解配置方式:
配置类主要代码如下:
// 配置类,相当于配置文件@Configurationpublic 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
为多实例:
@Configurationpublic class MainConfig3{ // 给容器中注册一个bean,类型为返回值的类型,默认是单实例 @Scope("prototype") @Bean public Person person(){ return new Person("yhl",19); }}
@Lazy
懒加载主要针对单实例bean
(单实例bean
默认在容器启动的时候创建对象),使用懒加载后,容器启动的时候不创建对象,仅当第一次使用(获取)bean
的时候才创建并初始化。
示例如下:
@Configurationpublic class MainConfig4{ // 给容器中注册一个bean,类型为返回值的类型,默认是单实例 @Lazy @Bean public Person person(){ return new Person("yhl",19); }}
@Conditional
条件注册bean当引入@Conditional
时, 容器可以选择性的注册bean
。比如,当操作系统为WINDOWS
时,注册yhl1
实例; 当操作系统为LINUX
时, 注册yhl2
实例:
// 配置类@Configurationpublic 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
有点简单。 bean
的id
为全类名IOC
容器,所有bean
的注册可以使用BeanDefinitionRegistry
,写YhlImportBeanDefinitionRegistrar
实现ImportBeanDefinitionRegistrar
接口即可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{ @Override public Monkey getObject() throws Exception { return new Monkey(); } @Override public Class getObjectType() { return Monkey.class; } @Override public boolean isSingleton() { return true; }}
@Configurationpublic class MainConfig9 { @Bean public YhlFactoryBean yhlFactoryBean(){ return new YhlFactoryBean(); }}
默认获取到的是工厂bean
调用getObject
创建的对象,要获取工厂bean
本身,需要在id
前加个yhlFactoryBean
。
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
进行销毁。@Componentpublic 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
将被移除之前进行通知,在容器销毁之前进行清理工作。@Componentpublic 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()
之后。/* * 后置处理器:初始化前后进行处理工作 * 将后置处理器加入到容器中 */@Componentpublic 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; }}
转载地址:http://briwi.baihongyu.com/