一. Spring基础
1. Eclipse安装
准备工作:
1. Spring插件
2. Spring jar包
2. 安装过程
help
–> install new software
–> add
–> archive
–> 找到本地spring插件
—> 只点击后缀带有spring IDE
的项 —> 联网更新去掉 —> eclipse重启
3. 导入jar包
把一下jar包加入到工程的classpath当中
- commons-logging-1.1.1.jar–>spring必须依赖的日志包
- beans
- context
- core
- expression
4. Spring HelloWorld程序
- 新建
Java project spring-1
- 新建
lib
–>导入jar
包–>bulid to path
4.1 HelloWorld类
package com.mozart.beans;
public class HelloWorld{
private String name;
public void setName(String name){
this.name=name;
}
public void hello(){
System.out.println("hello: "+name);
}
}
4.2 不使用Spring的测试代码
package com.mozart.beans;
public class Main{
public static void main(String[] args){
/1./创建HelloWorld对象
HelloWorld helloWorld=new HelloWorld();
//2.为name属性赋值
helloWorld.setName("mozart");
//3.调用方法
helloWorld.hello();
}
}
运行结果:
hello: mozart
4.3 配置xml文件
src
下创建一个Spring Bean configuration File
–>applicationContext.xml
在此处可以选择很多命名空间
。这就是安装的插件提供的。
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans"
>>
<bean id="helloWorld" class="com.atguigu.spring.beans.helloWorld">
<propertiy name="name2" value="Spring"></propertiy>>
</bean>>
</beans>>
4.4 使用Spring的HelloWorld程序
package com.mozart.beans;
public class Main{
public static void main(String[] args){
//1.创建Spring的IOC容器对象
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.从IOC容器当中获取Bean实例
HelloWorld helloWorld=(HelloWorld) ctx.getBean("helloWorld");
//3.调用方法
helloWorld.hello();
}
}
个人理解
1.ApplicationContext
就代表IOC
容器,它是一个接口。
2.ClassPathXmlApplicationContext
: 表示配置文件在类路径下.创建IOC容器
1. 会对配置文件当中配置的Bean进行初始化
2. 同时会对属性进行复制
二. Spring原理——IOC和DI
1. 名词解释
IOC(Inversion of control)
—->反转控制
1. 传统的资源查找方式:组件向容器发起请求查找资源。
2. IOC
: 容器主动地将资源推送给管理的组件。
DI(Dependency Injection)
—->依赖注入(和反转控制是一个意思)
2. 举例理解
需求: 容器中有两个类A和B。B中有个属性a依赖A。
要求获取B对象。
传统的方式:
A a=getA();
B b=getB();
b.setA(a);
IOC容器的方式:
容器自动把关联关系建立好了。
3. IOC的前生
- 分离接口与实现
- 工厂模式
- 采用反转控制
举例一个需求:
ReportService
类要用到报表生成器ReportGenerator
的接口。
ReportGenerator
的接口有两个实现类PDFReportGenerator
实现类
HtmlReportGenerator
实现类
1. 分离接口与实现
缺点: 耦合性太高
2. 工厂模式
缺点: 代码实现复杂
3. IOC容器
自动化方式,stay foolish!
三. Spring Bean的配置
1. Bean配置简介
1.1 Bean的配置形式
- 基于xml配置文件的方式
- 基于注解的方式
1.2 Bean的配置方式
- 通过全类名(反射)
- 通过工厂方法(静态工厂方法&实例工厂方法)
- FactoryBean
1.3 IOC容器
- BeanFactory
- ApplicationContext
1.4 依赖注入的方式
- 属性注入
- 构造器注入
2. IOC容器
在SpringIOC
容器读取Bean
配置,创建Bean
之前,必须要对IOC
容器进行初始化。只有对IOC容器初始化实例化完成了,
才能够从IOC
容器当中获取Bean
实例并使用。
Spring提供了两种类型的IOC
容器的实现方式:
BeanFactory
:Spring
框架的基本设施,IOC
容器的基本实现。ApplicationContext
提供了更多高级特性,是BeanFactory
的子接口。几乎所有的场合都使用ApplicationContext而不是BeanFactory.ConfigurableApplicationContext
是ApplicationContext
的子接口。ConfigurableApplicationContext
中有新的功能,比如refresh()
,close()
。让容器具有启动,刷新,关闭的功能。ConfigurableApplicationContext
有两个主要的实现类
ClassPathXmlApplicationContext
:从类路径下加载配置文件
FileSystemXmlApplicationContext
: 从文件系统当中加载配置文件。
ApplicationContext
在初始化的时候就实现了所有单例的Bean
。
非单例Bean
将在Bean
的作用域的时候再说。
WebApplicationContext
是专门为Web应用而准备的。
3. 通过IOC容器获取Bean
BeanFactory
当中具有获取Bean
的方法。
ListableBeanFactory
是继承了BeanFactory
。
ApplicationContext
是实现了ListableBeanFactory
所以,ApplicationContext
也具有了获取Bean
的方法。
通过ID: ID能够唯一定位Bean
new ClassPathXmlApplicationContext("applicationContext.xml").getBean("Bean的id");
通过类型class: 不能唯一定位,使用它要求Bean在容器中是唯一的。
new ClassPathXmlApplicationContext("applicationContext.xml").getBean(HelloWorld.class)
4. Bean的xml配置
id: 通过id来应用Bean,id必须是唯一的。
class: Bean的全类名,通过反射的方式在IOC容器当中创建Bean的实例,要求Bean当中有无参构造器
4.1 属性的依赖注入的方式
Spring
支持3种
依赖注入的方式
1.属性注入: 通过setter
方法为Bean
的属性注入值或者注入引用,开发当中最常用
<property name="name" value="Spring"></property>
2.构造器注入: 不提供setter
方法,通过构造器初始化的操作进行类中属性赋值。
没有name属性
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="Shanghai" index="1"></constructor-arg>
<constructor-arg value="300000" index="2"></constructor-arg>
这样写很容易产生歧义的。可能很多赋值都匹配一个构造器的。
解决方法如下:
<constructor-arg value="Audi" type="java.lang.String"></constructor-arg>
<constructor-arg value="Shanghai" type="java.lang.String"></constructor-arg>
<constructor-arg value="300000" type="double"></constructor-arg>
<constructor-arg type="int">
<value>250</value>
</constructor-arg>
属性值可以用value属性也可以使用value子节点进行赋值.
4.2 字面值注入
value
表示的字面值
字面值: 可以用字符串表示的值,可以通过元素标签或者value属性进行注入。
基本数据类型及其封装类,String类型都可以采用字面值注入的方式进行注入。
若字面值当中包含一些特殊字符的话,可以使用<![CDATA[]]>
把字面值包裹起来。
如下:
<constructor-arg index="1">
<value><!CDATA[<Shanghai^>]></value>
</constructor-arg>
4.3 Bean之间的引用配置
<bean id="person" class="com.atguigu.spring.beans.Person">
<property name="name" value="tom"></property>
<property name="age" value="tom"></property>
<!--可以使用property的ref属性建立bean之间的引用关系-->
<property name="car" ref="car2"></property>
<property name="car">
<ref bean="car2" />
</property>
</bean>
组成应用程序的Bean需要相互协助.
在Bean的配置文件当中,可以通过元素或者ref属性为Bean的属性或者构造器参数指定对Bean的引用。
也可以在属性或者构造器的内部包含一个bean的声明,这样的Bean称之为内部Bean。
4.4 内部Bean
<bean id="person" class="com.atguigu.spring.beans.Person">
<property name="name" value="tom"></property>
<property name="age" value="20"></property>
<!--可以使用property的ref属性建立bean之间的引用关系-->
<property name="car" ref="car2"></property>
<property name="car">
<bean class="com.atguigu.spring.beans.Car">
<contructor-arg value="Ford"></contructor-arg>
<contructor-arg value="Changan"></contructor-arg>
<contructor-arg value="200000" type="double"></contructor-arg>
</bean>
</property>
</bean>
内部Bean不用写id,不能够被外部引用的。
<bean id="person2" class="com.atguigu.spring.beans.Person">
<contructor-arg value="jerry"></contructor-arg>
<contructor-arg value="25"></contructor-arg>
<contructor-arg ref="car2"></contructor-arg>
</bean>
4.5 注入参数详解—null值和级联属性
可以使用专用的<null/>
元素标签为Bean的字符串或者其他对象类型的属性赋值为null值。
其实没有多大的意思,因为引用类型的默认都是null。
<bean id="person2" class="com.atguigu.spring.beans.Person">
<contructor-arg value="jerry"></contructor-arg>
<contructor-arg value="25"></contructor-arg>
<contructor-arg><null/></contructor-arg>
</bean>
Spring
支持级联属性的配置。(Bean当中的Bean的属性赋值)
注意,属性需要先初始化后,才可以为级联属性赋值。否则异常,和Struts2
不同。
<bean id="person2" class="com.atguigu.spring.beans.Person">
<contructor-arg value="jerry"></contructor-arg>
<contructor-arg value="25"></contructor-arg>
<contructor-arg ref="car"></contructor-arg>
<!--为级联属性赋值,这要求car这个类当中有setPrice方法-->
<property name="car.price" value="300000"></property>
</bean>
4.6 集合属性
一个人可以有好多辆车,人对象,车对象,怎么在xml当中配置bean。
使用节点为list的属性赋值
<list> <set> <map>
标签配置集合属性。
<bean id="person2" class="com.atguigu.spring.beans.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>
4.7 配置map属性值
使用map
节点以及map
的entry
子节点配置map
类型的成员变量。
<bean id="person2" class="com.atguigu.spring.beans.Person">
<property name="name" value="Mike"></property>
<property name="age" value="27"></property>
<property name="cars">
<map>
<entry key="AA" value-ref="car"></entry>
<entry key="BB" value-ref="car2"></entry>
</map>
</property>
</bean>
4.8 Properties
Properties
是HashTable
的一个子类,HashTable
是Map
的一个实现类.
到时候和hibernate
可以整合。
使用props
和prop
子节点来为properties
属性赋值.
<bean id="datasource" class="com.atguigu.spring.beans.collection.datasource">
<property name="properties">
<props>
<prop key="user">root</prop>
<prop key="password">1234</prop>
<prop key="jdbcurl">jdbc:mysql:///test</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
4.9 使用utility schema
定义集合
配置单例的集合Bean
,以供多个Bean
进行引用
引入新的util
命名空间。
<util:list id="cars">
<ref bean="car" />
<ref bean="car2" />
</util:list>
<bean id="person4" class="com.atguigu.spring.beans.collection.Person">
<property name="name" value="Jack"></property>
<property name="age" value="29"></property>
<property name="cars" ref="cars"></property>
</bean>
4.10 使用p命名空间
在Spring2.5
当中引入了新的命名空间,可以通过比较简化的方式配置bean
属性。
需要先导入p命名空间。
相对于传统的配置方式,更加简洁。
<bean id="person5" class="com.atguigu.spring.beans.collection.Person"
p:name="Queen" p:age="30" p:car-ref="cars"
></bean>
4.11 自动装配
Spring IOC
容器可以自动装配Bean
,需要做的就是仅仅是在<bean>
的autowire
属性当中指定自动装配的模式。
byType
(根据类型自动装配):
若IOC容器中有多个与目标Bean
类型一致的Bean
,
在这种情况下,Spring
将无法判定哪个Bean
最合适该属性
,所以不能执行自动装配。
byName
(根据名称自动装配):
必须将目标Bean
的名称和属性设置的完全相同。
constructor
(通过构造器自动装配):
将Bean
中存在多个构造器的时候,此种装配方式将会很复杂,不推荐使用.
举例说明
person
对象有name
,address
对象(city,street)
,car
对象(brand,price)
beansautowire.xml
代码
<bean id="address" class="com.atguigu.spring.beans.autowire.Address"
p:city="beijing"
p:street="HuiLongGuan"
>
</bean>
<bean id="car" class="com.atguigu.spring.beans.autowire.Car"
p:brand="Audi"
p:price="300000"
>
</bean>
<bean id="person" class="com.atguigu.spring.beans.autowire.person"
p:name="Tom"
p:address-ref="address"
p:car-ref="car"
>
<bean id="person" class="com.atguigu.spring.beans.autowire.person"
p:name="Tom" autowire="byType"
>
</bean>
byName
:根据bean
的名字和当前bean
的setter
方法的属性名进行自动装配,
若有匹配的,则进行自动装配,若没有匹配的,则不进行装配。
byType
根据Bean
的类型和当前bean
的属性的类型进行自动装配,若IOC容器当中有1个以上的类型匹配的bean,则抛出异常。
在Bean配置文件里设置autowire
属性进行自动装配将会装配Bean的所有属性,
然而,若只希望装配个别属性的时候,autowire
属性就不够灵活了。
autowire
属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼而有之。
一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。
但是在整合第三方框架的时候会使用autowire
,会给我们带来一些方便。
4.12 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
的class
属性去掉,就必须加上abstract=true
。
<bean id="address" class="com.atguigu.spring.beans.autowire.address"
p:city="Beijing" p:street="WuDaoKou" abstract="true"></bean>
<bean id="address2" p:street="DaZhongSi" parent="address"></bean>
<bean id="person" class="com.atguigu.spring.beans.autowire.person"
p:name="Tom" p:address-ref="address2" depends-on="car">
</bean>
Spring
允许用户通过depends-on
属性设定bean
前置依赖的bean
。
前置依赖的bean
会在本bean
实例化之前创建好。
如果前置依赖于多个bean
,则可以通过都好,空格或的方式配置bean的名称。
4.13 配置Bean的作用域
使用Bean
的scope
属性来配置bean
的作用域
singleton
: 默认值,容器初始时创建bean
实例,在整个容器的生命周期内只创建了这一个bean
,是单例的。
prototype
:原型的,容器初始化的时候并没有创建bean
实例,你请求bean
的时候,容器就创建一个bean
,再请求再创建,是不一样的bean
实例.
<bean id="Car" class="com.atguigu.spring.bean.beanscope" scope="singleton">
<property name="brand" value="Audi"></property>
<property name="price" value="200000"></property>
</bean>
4.14 使用外部属性文件
在配置文件里配置bean
的时候,有时候需要在bean
的配置里混入系统部署的细节信息(例如:文件路径,数据源配置信息等)
而这些部署细节实际上需要和bean
的配置相分离。
Spring
提供了一个PropertyPlaceholderConfigurer
的BeanFactory
后置处理器。
这个处理器允许用户将bean
配置的部分内容外移到属性文件当中。
可以在bean
配置文件里头使用形式为${var}
的变量
PropertyPlaceholderConfigurer
从属性文件里头加载属性,
并使用这些属性来替换变量。
Spring
还允许在属性文件里头使用$(propName)
,以实现属性之间的相互作用。
bean-property.xml配置一个数据源
导入c3p0-0.9.1.2.jar
加入mysql的驱动mysql-connector-java-5.1.7-bin.jar
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"></property>
<property name="password" value="1230"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///test"></property>
</bean>
<!-- 导入属性文件 -->
<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>
5. Spring表达式语言 :SpEL
5.1 SpEL简介
Spring
表达式语言(简称SpEL
):
是一个支持运行时查询和操作对象的强大的表达式语言
语法类似于EL
: SpEL
使用#{}
作为定界符,所有在大括号里头的字符都被认为是SpEL
SpEL
为bean
的属性进行动态赋值提供了便利。
通过SpEL
可以实现:
- 通过
bean
的id
对bean
进行引用 - 调用方法以及引用对象中的属性
- 计算表达式的值
- 正则表达式的匹配
5.2 SpEL字面量
字面量的表示:
整数: <property name="count" value="#{5}"></property>
小数: <property name="count" value="#{89.7}"></property>
科学计数法: <property name="count" value="#{1e4}"></property>
字符串: <property name="count" value="#{'chuck'}"></property>
布尔值: <property name="count" value="#{false}"></property>
如果是仅仅是赋字面值的话用SpEL的意义不大的。
5.3 引用其他对象
<property name="prefix" value="#{prefixGenerator}"></property>
相当于
<property name="prefix" ref="prefixGenerator"></property>
5.4 引用其他对象的属性
<property name="prefix" value="#{prefixGenerator.suffix}"></property>
调用其他方法,还可以链式操作(动态为属性进行赋值)
<property name="prefix" value="#{prefixGenerator.toString()}"></property>
<property name="prefix" value="#{prefixGenerator.toString().toUpperCase()}"></property>
5.5 运算符
算数运算符:+ - * / %, 加号可以作为字符串的连接符
比较运算符:< > == <= >= lt gt eq le ge
逻辑运算符: and or not
if-else运算符: ?():()
正则表达式:matches
5.6 调用静态方法或静态属性: T()
<property name="prefix" value="#{T(java.lang.Math).PI}"></property>
<bean id="address" class="com.atguigu.spring.beans.spel.Address">
<property name="city" value="#{'Beijing'}"></property>
<property name="street" value="Wudaokou"></property>
</bean>
6. IOC容器中Bean的生命周期
SpringIOC
容器可以管理Bean
的生命周期,Sprirng
允许在Bean
生命周期的特定点执行定制的任务。
6.1 Bean的生命周期管理过程
SpringIOC
容器对Bean
的生命周期进行管理的过程:
- 通过构造器或工厂方法创建bean实例。
- 为bean的属性设置值和对其他bean的引用
- 调用用bean的初始化方法
- bean可以使用了
- 当容器关闭时,调用bean的销毁方法
在bean的生命里设置init-method
和destroy-method
属性,为bean
指定初始化和销毁方法。
<bean id="car" class="com.atguigu.spring.beans.cycle.Car" init-method="init" destroy-method="destroy">
<property name="brand" value="Audi"></property>
</bean>
6.2 创建bean后置处理器
bean
后置处理器允许在调用初始化方法前后对Bean
进行额外的处理。
bean
后置处理器对IOC
容器里的所有bean
实例注意处理,
而非是单一实例。
其典型应用是:检查bean
属性的正确性或根据特定的标准更改bean
的属性。
对bena后置处理器而言,需要实现interface beanPostProcessor
接口。
在初始化方法被调用前后,Spring
将把每个bean
实例分别传递给上述接口的以下两个方法:
postProcessAfterInitialization(Object bean,String beanName);
postProcessBeforInitialization(Object bean,String beanName);
Spring IOC
容器对bean的生命周期进行管理的过程 :
- 通过构造器或工厂方法创建bean实例。
- 为bean的属性设置值和对其他bean的引用
- 将bean实例传递给Bean后置处理器的postPorcessBeforInitialization方法
- 调用bean的初始化方法
- 将bean实例传递给Bean后置处理器的postPorcessAfterInitialization方法
- bean可以使用了
- 当容器关闭的时候,调用bean的销毁方法
xml配置代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="car" class="com.atguigu.spring.beans.cycle.Car" init-method="init" destroy-method="destroy">
<property name="brand" value="Audi"></property>
</bean>
<!-- 配置bean的后置处理器 -->
<bean class="com.atguigu.spring.beans.cycle.MyBeanPostProcessor"></bean>
</beans>
后置处理器类代码
package com.atguigu.spring.beans.cycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessBeforeInitialization" + bean + "," + beanName);
//可以检查bean,这是通用的。
//可以创建一个新的bean,然后返回
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessAfterInitialization" + bean + "," + beanName);
return null;
}
}
后置处理器类代码
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessBeforeInitialization" + bean + "," + beanName);
//可以检查bean,这是通用的。
//可以创建一个新的bean,然后返回
if("car".equals(beanName)){
//....对bean进行过滤
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessAfterInitialization" + bean + "," + beanName);
Car car=new Car();
car.setBrand("Ford");
return car;
}
}
7. 通过工厂方法(静态工厂方法和实例工厂方法)配置bean
上面都是通过全类名反射配置bean
7.1 静态工厂方法
直接调用某一个类的静态方法就可以返回bean的实例
工厂类代码
public class StaticFactory{
private static Map<String,car> cars=new HashMap<String,Car>();
static{
cars.put("audi",new Car("audi",300000));
cars.put("ford",new Car("ford",400000));
}
//静态工厂方法
public static Car getCar(String name){
return cars.get(name);
}
}
xml配置代码
<!--通过静态工厂方法来配置bean,不是配置静态工厂方法实例,而是配置bean实例-->
<!--class属性指向静态工厂方法的全类名,factory-mehod指向静态工厂方法的方法名字
如果工厂方法需要传入参数,则使用constructor-arg来传递参数
-->
<bean id="car1" class="com.lingyao.StaticFactory" factory-method="getCar">
<constructor-arg value="audi"></constructor-arg>
</bean>
7.2 实例工厂方法
实例工厂的方法,也就是先创建工厂本身,再调用工厂的实例方法。
工厂类代码
public class InstanceCarFactory{
private Map<String,Car> cars=null;
public InstanceCarFactory(){
cars=new HashMap<String,Car>();
cars.put("audi",new Car("audi",300000));
cars.put("ford",new Car("ford",400000));
}
public Car getCar(String name){
return cars.get(name);
}
}
xml配置代码
<bean id="car1" class="com.lingyao.StaticFactory" factory-method="getCar">
<constructor-arg value="audi"></constructor-arg>
</bean>
8. FactoryBean配置方式
为什么要用FactoryBean?
配置bean
的时候要用到IOC
容器的其他bean
,用factoryBean
是最合适。
自定义FactoryBean
需要实现Spring
当中的一个接口叫做:FactoryBean
public class CarFactoryBean implements FactoryBean<Car>{
//返回bean的对象
private Stirng brand;
public void setBrand(String brand){
this.brand=brand
}
public Car getObejct() throws Exception{
return new Car("BMW",500000);
}
//返回bean的类型
public Class<?> getObjectType(){
return Car.class;
}
public boolean isSingleton(){
return true;
}
}
通过FactoryBean配置bean实例,class执行FactoryBean的全类名
property是FactoryBean的属性
但返回的实例就是FactoryBean中的getObject方法返回的一个bean
<bean id="car" class="com.lingyao.CarFactoryBean" factory-method="getCar">
<property name="brand" value="BMW"></property>
</bean>
9. 基于注解的方式配置bean
上面所有的配置bean的方式都是基于xml文件的方式进行配置的。
1. 基于注解配置bean
2. 基于注解配置bean的属性
9.1 在classpath中扫描组件
组件扫描(component scanning)
:Spring
能够从classpath
下自动扫描,侦测和实例化具有。特定注解的组件。
特定组件包括:
@Component
: 基本注解,标识了一个受Spring管理的组件。
@Respository
: 标识持久层组件
@Service
: 标识服务层(业务层)组件
@Controller
: 标识表现层组件
对于扫描到的组件,Spring
有默认的命名策略:
使用非限定类名,第一个字母小写.
也可以在注解中通过value
属性值标识组件的名称。
当在组件类上使用了特定的注解之后,
还需要在Spring的配置文件中声明
<context:componext-scan>
base-package
属性指定一个需要扫描的基类包,
Spring
容器将会扫描这个基类包里及其子包中的所有类。
当需要扫描多个包时,可以使用逗号分隔。
如果仅希望扫描特定的类而非基包下的所有类,
可以使用resource-pattern
属性过滤特定的类,示例:
<context:component-scan
base-package="com.atguigu.spring.beans"
resource-pattern="autowire/*.class" />
<context:include-filter> 子节点表示要包含的目标类
<context:exclude-filter> 子节点表示要排除在外的目标类
<context:component-scan> 下可以拥有若干个<comtext:include-filter>
和<context:exclude-filter>子节点。
比方说有很多包,包中所有的类都用注解标识上了,然后配置了context:component-scan
,就指定扫描那些包。
举例理解:
第一, 建立一个TestObject类,加上注解@
第二, 接口UserRepository
实现类 UserRepositoryImple
implements UserRepostory
注解@Repository
,模拟持久化层
第三: UserService
类,其中有个方法add(){}
方法
注解:@Service
第四: UerController
类,其中有个execute(){}
方法,
注解@Controller
.
创建bean
的配置文件—->beans-annotation.xml
,导入context
命名空间。
<!--指定spring ioc容器扫描的包-->
<context:component-san base-package="anotation">
<bean></bean>
9.2 过滤表达式
<context:include-filter>
和<context:exclude-filter>
支持多种类型的过滤表达式
annotation
: 所有标注了xxxAnnotation
的类
assinable
: 所有继承或扩展xxxService
的类
aspectj
: 所有类名以Service
结束的类以及继承或扩展它们的类。
该类型采用AspejctJ
进行过滤。
regex
:
所有com.atguigu.anno
包下的类。该类型采用正则表达式根据类的类名进行过滤。
custom
:
采用xxxTypeFilter
通过代码的方式定义过滤规则。该类必须实现
org.springframework.core.type.TypeFilter
接口
component–controller-repository-service
<!--指定spring ioc容器扫描的包-->
<bean>
<context:component-san base-package="com.atguigu.spring.beans.anotation">
<context:execlude-filter type="annotation" use-default-filter="true" expression="org.springframework.stereotype.Repository" />
</bean>
9.3 泛型依赖注入
BaseService —-> @Autowired BaseRepository
BaseRepository
User
UserService extends BaseService —-> @Service
UserRepository extends BaseRepository —-> @Repository
父类泛型之间建立引用的。
BaseService当中有个成员变量,或者方法是关于BaseRepository的。
这个变量或方法用@Autowired来自动装配。
这样,父类泛型之间就建立起了引用了。
子类指定user泛型的Service和UserRepository之间也就自动地建立了引用了。
然后在测试的时候,从IOC容器中拿到userService这个bean。调用其中的方法,就会自动装配对应的Repository子类了。
总结一下:
父类之间的引用关系,对应子类之间自动引用。
子类都用注解交给IOC管理之后,很容易调用对用子类泛型。