1.配置方式:基于XML文件的方式,基于注解的方式
2.Bean的配置方式:通过全类名(反射)、通过工厂方法啊(静态方法&实例化工厂方法)、FactoryBean
3.IOC容器BeanFactory&ApplicationContext
1.Spring允许继承bean的配置
2.子bean从父bean中继承配置,包括bean的属性配置
2.父bean可以作为模板,可以设置的abstract属性为true,这样就不会实例化bean
4.若一个bean的属性没有指定,则该bean必须为一个抽象bean
depends-on
<bean id="address" class="top.finen.spring.autowire.Address">
<property name="city" value="Shanghai"></property>
<property name="street" value="lujiazui"></property>
</bean>
<bean id="address2" class="top.finen.spring.autowire.Address" parent="address">
<!-- <property name="city" value="Shanghai"></property>-->
<property name="street" value="Waitang"></property>
</bean>
<bean id="address3" class="top.finen.spring.autowire.Address" parent="address2">
<!-- <property name="city" value="Shanghai"></property>-->
<property name="street" value="Waitang"></property>
</bean>
<bean id="car" class="top.finen.spring.autowire.Car">
<property name="brand" value="Audi"></property>
<property name="price" value="300000"></property>
</bean>
<!-- 要求在配置Person时,必须有一个关联的car,这个bean必须依赖于Car这个bean -->
<bean id="person" class="top.finen.spring.autowire.Person" depends-on="car">
<property name="name" value="Tom"></property>
<property name="address" ref="address3"></property>
</bean>
使用bean的scope属性来配置bean的作用域
默认值:singleton,容器初始化时创建bean实例,在整个容器的生命周期内只创建一个bean,单例的,初始化时就创建出来。
prototype:原型。在容器初始化时不创建bean的实例,而在每次请求时都创建一个新的bean实例,并返回
<!--
使用bean的scope属性来配置bean的作用域
默认值:singleton,容器初始化时创建bean实例,在整个容器的生命周期内只创建一个bean,单例的,初始化时就创建出来。
prototype:原型。在容器初始化时不创建bean的实例,而在每次请求时都创建一个新的bean实例,并返回
-->
<bean id="car"
class="top.finen.spring.autowire.Car"
scope="prototype">
<property name="brand" value="Audi"></property>
<property name="price" value="300000"></property>
</bean>
1.SpringIOC容器可以管理Bean的生命周期。
public class Car {
public Car() {
System.out.println("Car's Constructor");
}
private String brand;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
System.out.println("SetBrand...");
this.brand = brand;
}
public void init() {
System.out.println("init....");
}
public void destory() {
System.out.println("destory...");
}
}
2.SpringIOC容器可以对Bean的生命周期进行管理。
①.通过构造器或者工厂方法创建Bean实例。
Bean的后置处理器允许在调用初始化方法前后对Bean进行额外处理。
Bean后置处理器对IOC容器里的所欲Bean实例逐一处理。
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("postProcessBeforeInitialization " + o + "," + s);
return o;
}
@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("postProcessAfterInitialization " + o + "," + s);
return null;
}
}
<bean id="car" class="top.finen.spring.cycle.Car" init-method="init" destroy-method="destory"></bean>
<!--
实现BeanPostProcessor接口,并具体提供Object postProcessBeforeInitialization(Object o, String s):init-method之前被调用
和Object postProcessAfterInitialization(Object o, String s)的实现:init-method之后被调用
bean:bean实力本身
beanName:IOC容器配置的bean的名字
返回值:是实际上返回给用户的那个Bean,注意:可以再以上两个方法中修改返回的bean甚至返回一个新的bean。
-->
<!--配置bean的后置处理器,不需要配置id,IOC是一个自动识别BeanPostProcessor-->
②.为Bean的属性设置值和对其他的Bean的引用。
③.调用Bean的初始化方法
④.Bean的使用
⑤.当容器关闭时,调用Bean的销毁方法。
3.为Bean的声明里设置init-method和destory-method属性,为bean指定初始化和销毁方法
<!--通过静态方法来配置bean,不是通过配置静态工厂方法实例,而是配置bean实例-->
<!--
class属性:指向静态工厂方法全类名
factory-method: 指向静态工厂方法的名字
constructor-arg:如果工厂方法需要传入参数,则通过constructor-arg传入参数
-->
<bean id="car1"
class="top.finen.spring.beans.factory.StaticCarFactory"
factory-method="getCar">
<constructor-arg value="audi"></constructor-arg>
</bean>
<bean id="carFactory" class="top.finen.spring.beans.factory.InstanceCarFactory"></bean>
<!--
factory-bean属性:指向实例工厂方法的全类名
factory-method: 指向静态工厂方法的名字
constructor-arg:如果工厂方法需要传入参数,则通过constructor-arg传入参数
-->
<!--通过实例工厂方法来配置bean-->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="audi"></constructor-arg>
</bean>
/**
* 静态工厂方法:直接调用某一个类的静态方法就可以返回bean的实例
*/
public class StaticCarFactory {
private static Map<String, Car> cars = new HashMap<String, Car>();
static{
cars.put("audi", new Car("audi", 30000));
cars.put("ford", new Car("ford", 50000));
}
//静态工厂方法
public static Car getCar(String name) {
return cars.get(name);
}
}
/**
* 实例工厂方法:实例工厂的方法,既现需要创建工厂本身,再调用工厂的实例方法实例方法来返回bean的实例
*/
public class InstanceCarFactory {
private Map<String, Car> cars = null;
public InstanceCarFactory() {
cars = new HashMap<String, Car>();
cars.put("audi", new Car("audi", 30000));
cars.put("ford", new Car("ford", 50000));
}
public Car getCar(String brand) {
return cars.get(brand);
}
}
<!--
通过FactoryBean来配置Bean的实例
class:指向FactoryBean的全类名
property:配置FactoryBean的属性
但是实际返回的实例却是FactoryBean的getObject()方法返回的实例
-->
<bean id="car" class="top.finen.spring.beans.factorybean.CarFactoryBean">
<property name="brand" value="BMW"></property>
</bean>
//自定义的FactoryBean需要实现FactoryBean
public class CarFactoryBean implements FactoryBean<Car> {
private String brand;
/**
* @return 返回bean的对象
* @throws Exception
*/
@Override
public Car getObject() throws Exception {
return new Car(brand, 500000);
}
/**
*
* @return 返回bean的类型
*/
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
public void setBrand(String brand) {
this.brand = brand;
}
}
基于注解方法配置bean
使用注解来装配bean的属性
1.在classpath中扫描组件对于扫描到的组件,对于扫描的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写,也可以通过在注解中配置value属性值表示组件的名称
特定组件:
1.@Component:基本注解,标识一个手Spring管理的组件
2.@Repository:标识持久化组件
3.@Service:标识服务层(业务层)组件
4.@Controller:标识表现层组件
2.在组件类使用特定的注解以后,还需要在Spring的配置文件中声明<context:component-scan>
<context:include-filter>
子节点表示包含的目标类<context:exclude-filter>
子节点表示要排除在外的目标类<context:component-scan>
下可以拥有若干个<context:exclude-filter>
、<context:include-filter>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置自动扫描的包: 需要加入 aop 对应的 jar 包 -->
<!-- 可以通过resource-pattern指定扫描的类 -->
<!-- context:exclude-filter子节点排除那些指定的表达式的组件 -->
<!-- context:include-filter子节点指定包含那些表达式的组件,该子节点需要use-default-filters -->
<context:component-scan
base-package="top.finen.spring.beans.annotation">
<!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>-->
<!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>-->
<!-- <context:exclude-filter type="assignable" expression="top.finen.spring.beans.annotation.repository.UserRepository"/>-->
</context:component-scan>
</beans>
@Component
public class TestObject {
}
@Service
public class UserService {
public void add() {
System.out.println("UserService add...");
}
}//其中一个示例
@Autowired注解自动装配具有兼容类型的单个Bean属性
构造器,普通字段,一切具有参数的方法都可以使用@Autowired注解。
@Autowired
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
//以上两种方法都可以
默认情况下,所有使用@Autowired注解的属性都需要被设置,当Spring招不到匹配的Bean装配置是,会抛异常。当某一属性允许不被设置,可以设置@Autowired注解的required属性为false。
默认情况下,当IOC容器里面存在多个类型兼容的Bean时,通过类型的自动装配将无法工作,此时可以在@Qualifier注解里提供Bean的名称,Spring允许对方法的入参标注@Qualifier已指定注入Bean的名称。
//使用Qualifier注解指定
@Autowired
@Qualifier("userRepositoryImpl")
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Autowired注解也可以应用在数组类型的属性上,此时Spring将会把所有匹配的Bean进行自动装配。
@Autowired也可以应用在集合属性上,此时Spring读取该集合的类型信息,然后自动装配所有与之配置的Bean。
Autowired注解在java.util.Map上时,若该Map的键值为String,那么Spring将自动装配与之Map类型兼容的Bean,此时Bean得到名称作为键值。
public class BaseService<T> {
@Autowired
protected BaseRepository<T> repository;
public void add() {
System.out.println("add...");
System.out.println(repository);
}
}
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-generic.di.xml");
UserService userService = (UserService) ctx.getBean("userService");
userService.add();
}
}