文章目录
spring是什么
-
spring是一个开源框架
-
spring为简化企业级应用开发而生。使用spring可以使简单的javaBean实现以前只有EJB才能实现的功能
-
spring是一个IOC(DI)和AOP容器框架
-
具体描述Spring
- 轻量级:Spring是非侵入性的——基于Spring开发的应用中的对象可以不依赖于Spring的API
- 依赖注入DI——控制反转IOC
- 面向切面编程AOP
- 容器:spring是一个容器,因为它包含并且管理应用对象的生命周期
- 框架:spring实现了使用简单的组件配置组合成一个复杂的应用。在spring中可以使用XML和java注解组合这些对象
- 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上spring自身也提供了展现层的springMVC和持久层的springJDBC)
-
spring模块
- Data Access/Integration
- JDBC ORM OXM JMS Transactions
- Web
- WebSocket Servlet Web Portlet
- AOP
- Aspects
- Instrumentation 整合
- Messaging 消息
- Core Container
- Beans Core Context SpEL
- Data Access/Integration
spring的bean的配置
IOC和DI
- IOC:其思想是反转资源获取的方向。传统的资源查找方式要求组件向容器发起请求查找资源。作为回应,容器适时的返回资源。而应用了IOC之后,则是容器主动地将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源。这种行为也被称为查找的被动形式。
- DI——IOC 的另一种表述形式:即组件以一些预先定义好的方式(例如:setter方法)接受来自如容器的资源注入。相对于IOC而言,这种表述更直接。
IOC前生——分离接口与实现
- 需求,生成HTML或PDF格式的不同类型的报表。
IOC前生——采用工厂设计模式
IOC——采用反转控制
基于XML的方式配置Bean
内容提要
- 配置bean——基于XML的方式
- bean的配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean
- IOC容器BeanFactory & ApplicationContext概述
- 依赖注入的方式:属性注入;构造器注入
- 注入属性值细节
- 自动转配
- bean之间的关系:继承;依赖
- bean的作用域:singleton;prototype;web环境作用域
- 使用外部属性文件
- spEL
- IOC容器中Bean的生命周期
- Spring4.x新特性:泛型依赖注入
在spring的IOC容器里配置bean
- 在xml文件中通过bean节点来配置bean
<!-- 通过全类名的方式配置bean-->
<bean id="HelloWorld" class="com.springbeantest.HelloWorld">
</bean>
- id:Bean的名称
- 在IOC容器中必须是唯一的
- 若id没有指定,spring自动将权限定性类名作为Bean的名字
- id可以指定多个名字,名字之间可用逗号、分号或空格分隔
- class:bean的全类名,通过反射的方式在IOC容器中创建Bean,所以要求bean中必须有无参的构造器
spring容器
- 在springIOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化,只有在容器实例化后,才可以从IOC容器中获取Bean实例并使用
- Spring提供了两种类型IOC容器实现
- BeanFactory (接口) :IOC容器的基本实现
- ApplicationContext (接口):提供了更多的高级特性,是BeanFactory的子接口。
- BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向使用Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory
- 无论使用何种方式,配置文件是相同的。
ApplicationContext
- ApplicationContext的主要实现类:
- ClassPathXmlApplicationContext:从类路径下加载配置文件
- FileSystemXmlApplicationContext:从文件系统中加载配置文件
- ConfigurableApplicationContext扩展于ApplicationContext,新增加两个主要方法refresh()和close(),让ApplicationContext具有启动、刷新和关闭上下文的能力 是ApplicationContext的实现类,是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext的父类
- ApplicationContext在初始化上下文时就实例化所有单例的Bean
- WebApplicationContext是专门为Web应用而准备的,它允许从相对于Web根目录的路径中完成初始化工作。
从IOC容器中获取Bean
- 调用ApplicationContext中的getBean()方法
//以id获取bean(唯一)
HelloWorld helloWorld = (HelloWorld) ctx.getBean("HelloWorld");
//以类型(可能不唯一)返回IOC容器中的bean,但要求IOC容器中必须只能有一个该类型的bean
HelloWorld helloWorld2 = (HelloWorld) ctx.getBean(HelloWorld.class);
依赖注入的方式
- spring支持3种依赖注入的方式
- 属性注入
- 构造器注入
- 工厂方法注入(很少使用,不推荐)
属性注入
- 属性注入即通过setter方法注入bean的属性值或依赖的对象
- 属性注入使用
<property>元素,使用name属性指定Bean的属性名称,value属性或<value>子节点指定属性值 - 属性注入是实际应用中最常用的注入方式
<bean id="HelloWorld" class="com.springbeantest.HelloWorld">
<property name="name" value="Spring"></property>
</bean>
构造方法注入
- 通过构造方法注入bean的属性值或依赖的对象,它保证了bean实例在实例化后就可以使用。
- 构造器注入在
<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性。
<bean id="Car2" class="com.springbeantest.Car">
<constructor-arg value="Baoma" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="240" type="int"></constructor-arg>
</bean>
public Car(String brand, String corp, int maxSpeed) {
this.brand = brand;
this.corp = corp;
this.maxSpeed = maxSpeed;
}
*字面值
- 字面值:可用字符串表示的值,可以通过
<value>元素标签或value属性进行注入 - 基本数据类型及其封装类、String等类型都可以采取字面值注入的方式
- 若字面值中包含特殊字符,可以使用
<![CDATA[]]>把字面值包裹起来。
<bean id="Car2" class="com.springbeantest.Car">
<constructor-arg value="Baoma" index="0"></constructor-arg>
<constructor-arg index="1">
<value><![CDATA[<ShangHai>]]></value>
</constructor-arg>
<constructor-arg value="240" type="int"></constructor-arg>
</bean>
引用其它Bean
- 组成应用程序的Bean经常需要互相协作以完成应用程序中的功能。要使Bean能够互相访问,就必须在Bean配置文件中指定对Bean的引用
- 在Bean的配置文件中,可以通过
<ref>元素或ref属性为bean的属性或构造器参数指定对Bean的引用 - 也可以在属性或构造器里包含对bean的声明,这样的bean称为内部bean
<bean id="person" class="com.springbeantest.Person">
<property name="name" value="Tom"></property>
<property name="age" value="24"></property>
<!-- 使用ref属性建立bean之间的引用关系-->
<property name="car" ref="Car2"></property>
</bean>
内部Bean:
<property name="car" >
<!-- 内部bean不能被外部引用-->
<bean class="com.springbeantest.Car">
<constructor-arg value="Ford" index="0"></constructor-arg>
<constructor-arg value="Beijing" index="1"></constructor-arg>
<constructor-arg value="200000" index="2"></constructor-arg>
</bean>
</property>
注入参数详解:null值和级联属性
- 可以使用专用的元素标签
<null/>为Bean的字符串或其他对象类型的属性注入null值 - 和Struts 、Hiberante等框架一样,spring支持级联属性的配置。属性需要先初始化后才可以为级联属性赋值,否则会有异常
<property name="car" ref="Car2"></property>
<property name="car.maxSpeed" value="250"></property>
集合属性
- 在Spring中可以通过一组内置的xml标签(如
<list>,<set,<map>)来配置集合属性 - 配置java.util.List类型的属性,需要指定
<list>标签,在标签里包含一些元素。这些标签可以通过<value>指定简单的常量值,通过<ref>指定对其他Bean的引用,<bean>指定内置bean定义。通过<null/>指定空元素,甚至可以内嵌其他集合 - 数组的定义和List一样,都使用
<list> - 配置java.util.Set需要使用标签
<set>,定义元素的方法和List一样。
<!-- 测试集合属性-->
<bean id="person3" class="com.springbeantest.beans.collections.Person">
<property name="name" value="Mike"></property>
<property name="age" value="27"></property>
<property name="cars">
<list>
<ref bean="Car"/>
<ref bean="Car2"/>
</list>
</property>
</bean>
<map>可以使用多个<entry>作为子标签,每个条目包含一个键和一个值- 必须在
<key>里定义键 - 因为键和值的类型没有限制,可以自由的给它们指定
<value>,<ref>,<bean>或<null/>元素 - 可以将
<map>的键和值作为<entry>的属性定义:简单常量使用key和value来定义;Bean引用通过key-ref和value-ref属性定义 - 使用
<props>定义java.util.Properties,该标签使用多个<prop>作为子标签,每个<prop>标签必须定义key属性
map:
<map>
<entry key="AA" value-ref="Car"></entry>
<entry key="BB" value-ref="Car2"></entry>
</map>
Properties :
public class DataSource {
private Properties properties;
@Override
public String toString() {
return "DataSource{" +
"properties=" + properties +
'}';
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
<bean id="dataSource" class="com.springbeantest.beans.collections.DataSource">
<property name="properties">
<props>
<prop key="user">root</prop>
<prop key="password">123456</prop>
<prop key="jdbcUrl">jdbc:mysql:///test</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
使用utility scheme定义集合
- 使用基本的集合标签定义集合时,不能将集合作为独立的bean定义,导致其它bean无法引用该集合,所以无法在不同bean之间共享集合
- 可以使用util.schema里的集合标签定义独立的集合bean,需要注意的是,必须在
<bean>根元素里添加util.schema定义
<util:list id = "cars">
<ref bean="Car" />
<ref bean="Car2" />
</util:list>
<bean id="person5" class="com.springbeantest.beans.collections.Person">
<property name="name" value="Jack"></property>
<property name="age" value="29"></property>
<property name="cars" ref="cars"></property>
</bean>
使用p命名空间
- 为了简化xml文件的配置,越来越多的xml文件采用属性而非子元素配置信息
- Spring从2.5版本开始引入了一个新的p命名空间。可以通过
<bean>元素属性的方式配置bean的属性。 - 使用p命名空间后,基于XML的配置方式将进一步简化。
<bean id="person6" class="com.springbeantest.beans.collections.Person"
p:age ="30" p:name="Queen" p:cars-ref="cars"></bean>
xml配置里的bean自动装配
- SpringIOC容器可以自动装配Bean,需要做的是在
<bean>中的autowire属性里指定自动装配的模式 - byType(根据类型自动装配):若IOC容器中有多个与目标Bean类型一致的bean,在这种情况下,spring将无法判定哪个bean最合适该属性,所以不能执行自动装配。
根据bean的类型和当前bean的属性的类型进行自动装配,若IOC容器中有1个以上的类型匹配的bean,则抛异常org.springframework.beans.factory.UnsatisfiedDependencyException
- byName(根据名字自动装配):必须将目标Bean的名称和属性名设置的完全相同
根据bean的名字和当前bean的setter风格的属性名进行自动装配,若有匹配的,则进行自动装配,若没有匹配的,则不装配
<!-- 自动装配 byName-->
<bean id="person" class="com.springbeantest.beans.autowire.Person"
p:name="Tom" autowire="byName"></bean>
-
constructor(根据构造器自动装配):当Bean中存在多个构造器时,这种自动装配方式将会很复杂,不推荐使用。
-
自动装配的缺点:
- 在bean配置文件里设置autowire属性进行自动装配将会配置bean的所有属性,然而,若只希望配置个别属性时,autowire属性就不够灵活了。
- autowire属性要么根据类型装配,要么根据名称自动装配,不能二者兼而有之
- 一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能带来的好处相比,明确清晰的配置文档更有说服力一些。
继承bean配置
- spring允许继承bean配置,被继承的bean称为父bean,继承这个父bean的bean叫做子bean
- 子Bean从父Bean中继承配置,包括Bean的属性配置
- 子Bean也可以覆盖从父Bean继承过来的配置
- 父Bean可以作为配置模板,也可以作为Bean实例,若只想把父Bean作为模板,可以设置Bean的abstract属性为true,这样spring就不会实例化这个bean
- 并不是Bean元素里的所有属性都会被继承,比如:autowire,abstract等。
- 也可以忽略父Bean的class属性,让子Bean指定自己的类,而共享相同的属性配置,但此时abstract必须设为true。
子bean和父bean配置:
<bean id="beijing" class="com.springbeantest.beans.autowire.Address"
p:city="Beijing"></bean>
<bean id="address2" parent="beijing" p:street="Wudaokou"></bean>
打印结果:
Address{city='Beijing', street='null'}
Address{city='Beijing', street='Wudaokou'}
依赖bean配置
- spring允许用户通过depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在Bean实例化之前创建好
- 如果前置依赖于多个Bean,则可以通过逗号,空格或的方式配置Bean的名称
person3依赖于car2,如果没有car2的话,会报错
<!-- bean 依赖-->
<bean id="person3" class="com.springbeantest.beans.autowire.Person"
p:name="Jack" p:address-ref="address2" depends-on="car2"></bean>
但是有car2的bean,打印结果car属性是null:
Person{name='Jack', address=Address{city='Beijing', street='Wudaokou'}, car=null}
Bean的作用域
代码测试:
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-autowire.xml");
Person person = (Person) ctx.getBean("person4");
Person person2 = (Person) ctx.getBean("person4");
System.out.println(person == person2);
- 默认是singleton :true
- 设定为prototype:false
使用外部属性文件
- 在配置文件里配置Bean时,有时需要在Bean的配置里混入系统部署的细节信息(例如:文件路径,数据源配置信息等)。而这些部署细节实际上需要和Bean配置相分离
- Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户将Bean配置的部分内容外移到属性文件中,可以在Bean配置文件里使用形式为${var}的变量,PropertyPlaceholderConfigurer从属性文件里加载属性,并使用这些属性来替换变量
- spring还允许在属性文件里使用${propName},以实现属性之间的相互引用。
<!-- 导入属性文件-->
<context:property-placeholder location="classpath:db.properties" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">">
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
<property name="driverClass" value="driverclass"></property>
<property name="jdbcUrl" value="${jdbcurl"></property>
</bean>
db.properties文件:
user=root
password = 123
driverclass = com.sql.jdbc.Driver
jdbcurl = jdbc:mysql:///test
Spring表达式语言:SpEL
- Spring表达式语言:是一个支持运行时查询和操作对象图的强大的表达式语言。
- 语法类似于EL: SpEL使用#{…}作为定界符,所有在大框号中的字符都将被认为是SpEL
- SpEL为bean的属性进行动态赋值提供了便利
- 通过SpEL可以实现
- 通过bean的id对bean进行引用
- 通过方法以及引用对象中的属性
- 计算表达式的值
- 正则表达式的匹配
SpEL:字面量
- 字面量的表示:
- 整数
#{5} - 小数
#{1.5} - 科学计数法
#{1e5} - 字符串:可以使用单引号或多引号作为字符串的定界符号。
#{"cshvjd"}或#{'cshvjd'} - 布尔值:
#{false}
- 整数
SpEL:引用Bean、属性和方法
- 引用其它对象
<property name="car" value="#{car}"></property> - 引用其他对象的属性
<property name="address" value="#{car.price}"></property> - 调用其他方法,还可以链式操作
<property name="name" value="#{car.toString()}"></property>
方法的连接:<property name="name" value="#{car.toString().toUpperCase()}"></property> - 调用静态方法或静态属性:通过T()调用一个类的静态方法,它将返回一个Class Object,然后再调用相应的方法或属性
#{T(java.lang.Math).PI}
SpEL:支持的运算符号
- 算数运算符:+,-,*,/,%,^
- 加号还可以用作字符串连接
- 比较运算符:<,>,==,<=,>=,lt, gt。eg,le,ge
- 逻辑运算符 and,or,not,|
- if-else运算符:?:
- if-else的变体
- 正则表达式: matches
代码测试:
<bean id="address" class="com.springbeantest.beans.spel.Address"
p:city="#{'Wuhan'}" p:street="LuoYuRoad"></bean>
<bean id="car" class="com.springbeantest.beans.spel.Car"
p:brand="Audi" p:price="500000" p:tyrePerimeter="#{T(java.lang.Math).PI*80}"></bean>
<bean id="person" class="com.springbeantest.beans.spel.Person">
<property name="name" value="Jack"></property>
<property name="city" value="#{address.city}"></property>
<property name="car" value="#{car}"></property>
<property name="info" value="#{car.price>50000?'金领':'白领'}"></property>
</bean>
IOC容器中Bean的生命周期
- SpringIOC容器可以管理Bean的生命周期,Spring允许在Bean生命周期的特定点执行定制的任务
- SpringIOC容器对Bean的生命周期进行管理的过程
- 通过构造器或工厂方法创建Bean实例
- 为Bean的属性设置值和对其他Bean的引用
- 调用Bean的初始化方法
- Bean可以使用了
- 当容器关闭时,调用Bean的销毁方法
- 在Bean的声明里设置init-method和 destroy-method属性,为Bean指定初始化和销毁方法。
创建Bean后置处理器
- Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理
- Bean后置处理器对IOC容器里的所有Bean实例逐一处理,而非单一实例,其典型应用是:检查Bean属性的正确性或根据特定的标准更改Bean的属性
- 对Bean后置处理器而言,需要实现BeanPostProcessor接口。在初始化方法被调用前后,Spring将把每个Bean实例分别传递给该接口的两个方法
- postProcessBeforeInitialization()
- postProcessAfterInitialization()
- Bean后置处理器的作用:
- 可以通过实现BeanPostProcessor接口,并具体提供上面的两个方法,来构造自己的Bean后置处理器
- 方法里的参数:
- bean:bean本身
- beanName:IOC容器配置的bean名字
- 返回值:是实际上返回给用户的那个Bean,注意,可以在以上两个方法中修改返回的bean,甚至返回一个新的Bean
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
添加Bean后置处理器后Bean的生命周期
- 通过构造器或工厂方法创建Bean实例
- 为Bean的属性设置值和对其他Bean的引用
- 将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization方法
- 调用Bean的初始化方法
- 将Bean实例传递给Bean后置处理器的postProcessAfterInitialization方法
- Bean可以使用了
- 当容器关闭时,调用Bean的销毁方法
代码测试:
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-properties.xml");
// System.out.println(ctx.getBean("car"));
System.out.println("=======================");
System.out.println(ctx.getBean("car2"));
ctx.close();
}
}
class MyBeanPostProcessor implements BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization: " + bean + "," + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization: " + bean + "," + beanName);
return bean;
}
}
配置:
<!-- 配置bean的后置处理器:不需要配置id,IOC容器自动识别是一个BeanPostProcessor -->
<bean class="com.springbeantest.beans.cycle.MyBeanPostProcessor"></bean>
结果:
postProcessBeforeInitialization: Address{city='Wuhan', street='LuoYuRoad'},address
postProcessAfterInitialization: Address{city='Wuhan', street='LuoYuRoad'},address
postProcessBeforeInitialization: Car{brand='Audi', price=500000.0, tyrePerimeter=251.32741228718345},car
postProcessAfterInitialization: Car{brand='Audi', price=500000.0, tyrePerimeter=251.32741228718345},car
postProcessBeforeInitialization: Person{name='Jack', car=Car{brand='Audi', price=500000.0, tyrePerimeter=251.32741228718345}, city='Wuhan', info='金领'},person
postProcessAfterInitialization: Person{name='Jack', car=Car{brand='Audi', price=500000.0, tyrePerimeter=251.32741228718345}, city='Wuhan', info='金领'},person
Car's constructing
setBrand ...
postProcessBeforeInitialization: Car{brand='Cycle'},car2
init...
postProcessAfterInitialization: Car{brand='Cycle'},car2
=======================
Car{brand='Cycle'}
destroy...
通过调用工厂方法创建Bean——静态工厂方法
- 调用静态工厂方法创建Bean是将对象创建的过程封装到静态方法中。当客户端需要对象时,只需要简单的调用静态方法,而不用关心对象创建的细节
- 要声明通过静态方法创建的bean,需要在Bean的class属性里指定拥有该工厂的方法的类,同时在factory-method属性里指定工厂方法的名称,最后,使用construor-arg元素为工厂方法传递方法参数
代码测试:
<!-- 通过静态工厂方法来配置bean,注意不是配置静态工厂方法实例,而是配置bean实例-->
<!-- class属性:指向静态工厂方法的全类名
factory-method:指向静态工厂方法的名字
constructor-arg:如果工厂方法需要传入参数,则使用该标签类配置参数
-->
<bean id="car1" class="com.springbeantest.beans.factory.StaticCarFactory"
factory-method="getCar">
<constructor-arg value="audi"/>
</bean>
/*
静态工厂方法:直接调用某一个类的静态方法就可以返回Bean的实例
*/
public class StaticCarFactory {
private static Map<String , Car> cars = new HashMap<>();
static {
cars.put("audi",new Car("audi",3000000));
cars.put("ford",new Car("ford",4000000));
}
//静态工厂方法
public static Car getCar(String name) {
return cars.get(name);
}
}
通过调用工厂方法创建Bean——实例工厂方法
- 实例工厂方法:将对象的创建过程封装到另外一个对象实例的方法里。当客户端需要请求对象时,只需要简单的调用该实例方法而不需要关心对象的创建细节
- 要声明通过实例工厂方法创建的bean
代码测试:- 在Bean的factoty-bean属性里指定拥有该工厂方法的Bean
- 在factory-method属性中指定该工厂方法的名称
- 使用construor-arg元素为工厂方法传递方法参数
<!-- 实例工厂方法-->
<!-- 配置工厂的实例-->
<bean id="carFactory" class="com.springbeantest.beans.factory.InstanceCarFactory"></bean>
<!-- 通过示例工程的方法来配置bean-->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="ford"/>
</bean>
/*
实例工厂方法:需要创建工厂本身,再调用工厂的实例方法返回bean的实例
*/
public class InstanceCarFactory {
private static Map<String , Car> cars = null;
public InstanceCarFactory(){
cars = new HashMap<>();
cars.put("audi",new Car("audi",3000000));
cars.put("ford",new Car("ford",4000000));
}
public Car getCar(String brand){
return cars.get(brand);
}
}
通过FactoryBean创建Bean
<!-- FactoryBean
class指向FactoryBean的quanleim
property:配置FactoryBean的属性
但实际返回的实例却是FactoryBean的getObject()方法返回的实例
-->
<bean id="cars" class="com.springbeantest.beans.factory.CarFactoryBean">
<property name="brand" value="BMW"></property>
</bean>
package com.springbeantest.beans.factory;
import com.springbeantest.beans.spel.Car;
import org.springframework.beans.factory.FactoryBean;
public class CarFactoryBean implements FactoryBean<Car> {
private String brand;
public void setBrand(String brand) {
this.brand = brand;
}
@Override
public Car getObject() throws Exception {
return new Car(brand,5000000);
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
基于注解的方式配置Bean
在classpath中扫描组件
- 组件扫描(component scanning):Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件
- 特定组件包括
- @Component:基本注解,标识了一个受Spring管理的组件
- @Respository:标识持久层组件
- @Service:标识服务层(业务层)组件
- @Controller:标识表现层组件
- 对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写。也可以在注解中通过value属性值标识组件的名称
- 当在组件类上使用了特定的注解之后,还需要在Spring的配置文件中声明
<context:component-scan>:- base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包里及其子包中所有类
- 当需要扫描多个包时,可以用逗号分隔。
- 如果仅需要扫描特定的类而非基类包下的所有类,可使用resource-pattern属性过滤特定的类,例如
<context:component-scan base-package="com.springbeantest.beans.annotation" resource-pattern="repository/*.class"> </context:component-scan> <context:include-filter>:子节点标识要包含的目标类<context:exclude-filter>:子节点标识要排除在外的目标类<context:component-scan>下可以拥有若干个<context:include-filter>和<context:exclude-filter>子节点。<context:include-filter>和<context:exclude-filter>子节点支持多种类型的过滤表达式
| 类别 | 实例 | 说明 |
|---|---|---|
| annotation | com.atguigu.XxxAnnotation | 所有标注了XxxAnnotation的类。该类型采用目标类是否标注了某个注解进行过滤 |
| assinable | com.atguigu.XxxService | 所有继承或扩展了XxxService 的类。该类型采用目标类是否继承或扩展某个特定类进行过滤 |
| aspectj | com.atguigu…"Service+ | 所有类名以Service结束的类以及继承或扩展它们的类。该类型采用AspectJ表达式进行过滤 |
| regex | com.\atguigu.anno…* | 所有com.atguigu.anno包下的类。该类型采用正则表达式根据类的类名进行过滤 |
| custom | com.atguigu.XxxTypeFilter | 采用XxxTypeFilter通过代码的方式定义过滤规则。该类必须实现org.springframework.core.type.TypeFilter 接口 |
组件装配
<context:component-scan>元素还会自动注册AutowiredAnnotationBeanPostProcessor实例,该实例可自动装配具有@Autowired @Resource @Inject 注解的属性- @Autowired 注解自动装配具有兼容类型的单个Bean属性
- 构造器,普通字段(即使是非public),一切具有参数的方法都可以应用@Autowired注解
- 默认情况下,所有使用@Autowired注解的属性都需要被设置。当Spring找不到匹配的Bean装配属性时,会抛出异常,若某一属性允许不被设置,可以设置@Autowired注解的required属性为false设置required属性为false之后,即便找不到某个属性,也可以作为null来处理,而不是直接报错
- 默认情况下,当IOC容器中存在多个类型兼容的Bean时,通过类型的自动装配将无法工作,此时可以在@Qualifier注解里提供Bean的名称。Spring允许对方法的入参标注@Qualifier 以指定注入Bean的名称@Autowired
@Qualifier(“userRepositoryImpl”)
private UserRepository userRepository; 或
public void setUserRepository(@Qualifier(“userRepositoryImpl”) UserRepository userRepository) {
this.userRepository = userRepository;
} - @Autowired 注解也可以应用在数组类型的属性上,此时Spring将会把所有匹配的Bean进行自动转配。
- @Autowired 注解也可以应用在集合属性上,此时Spring读取该集合的类型信息,然后自动装配所有与之兼容的Bean。
- @Autowired 注解用在java.util.Map上时,若该Map的键值为String,那么Spring将自动装配与之Map值类型兼容的Bean,此时Bean的名称作为键值。
- Spring还支持@Resource @Inject 注解,这两个注解和 @Autowired注解的功能类似
- @Resource注解要求提供一个Bean名称的类属性,若该属性为空,则自动采用标注处的变量或方法名作为Bean的名称
- @Inject和@Autowired注解一样也是按类型匹配注入的Bean,但没有required属性
- 建议使用@Autowired注解
Spring4.x新特性:泛型依赖注入
Spring4.x可以为子类引入子类对应的泛型类型的成员变量的引用

本文深入解析Spring框架的核心概念,包括依赖注入、面向切面编程、容器管理及Bean配置方式,详细介绍基于XML的配置方法,如属性注入、构造器注入、工厂方法注入等,并探讨Bean的作用域、生命周期及依赖管理。
1321

被折叠的 条评论
为什么被折叠?



