一、spring容器创建bean的简单步骤
1、扫描被@Service,@Component等注解标识的类。
2、找到类的构造方法
默认使用无参构造方法构建bean,如果类中定义了有参构造方法则会按照有参构造方法构建bean。
3、依赖注入
如果类中存在@Autowired或有参的构造方法,会先从单例池获取对象,如果单例池没有对象则会创建对象,之后在放入单例池中 。如果有构造方法,会在注入完成后去执行该方法,进行一些属性的配置等。
4、执行spring的其他机制
(1)、实现aware类型的接口则会去执行相对应的set方法;
(2)、实现InitializingBean接口则会执行对应afterProperties方法;
(3)、系统定义了实现BeanPostProcessor接口的类,会在创建每一个bean之前执行(postProcessBeforeInitialization)和之后执行(postProcessAfterInitialization)方法等等。
5、使用bean
(1)、使用@Autowired,@Resource注解注入
(2)、被扫描的类存在构造方法,构造方法参数中获取bean。常用于当前bean的其他属性赋值。
二、自定义构造方法创建bean代码示例
1、创建统一的出售服务SailService
import com.zw.study.springBean.dto.Fruit;
public interface SailService {
String getFruitType(); // 定义类型,用于区分实现类
void addOrder(Fruit fruit);
}
2、实例化苹果和梨的SailService
// 苹果的实现类
import com.zw.study.springBean.dto.Fruit;
import com.zw.study.springBean.service.SailService;
import org.springframework.stereotype.Service;
@Service
public class AppleSailServiceImpl implements SailService {
@Override
public String getFruitType() {
return "apple";
}
@Override
public void addOrder(Fruit fruit) {
System.out.println("新增苹果的订单");
}
}
// 梨子的实现类
import com.zw.study.springBean.dto.Fruit;
import com.zw.study.springBean.service.SailService;
import org.springframework.stereotype.Service;
@Service
public class PearSailServiceImpl implements SailService {
@Override
public String getFruitType() {
return "pear";
}
@Override
public void addOrder(Fruit fruit) {
System.out.println("新增梨子的订单");
}
}
3、订单服务根据业务类型选择不同Service去执行(自定义构造方法)
import com.zw.study.springBean.dto.Fruit;
import com.zw.study.springBean.service.SailService;
import com.zw.study.springBean.service.FruitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
@Service
public class FruitServiceImpl implements FruitService {
// 所有销售服务的封装Map
private Map<String, SailService> fruitSailServiceMap = new HashMap<>();
// 说明:本例中因为SailService有多个实现类,需要区分业务在不同情况下选择不同的类去执行,所以不能直接通过@Autowired去注入SailService服务,所以这里需要创建Map将所有的SailService都获取到,之后业务在根据自己的需要选择Service去执行。
// 这里的Map是FruitServiceImpl的一个属性。本例通过指定带参的构造方法去封装属性。spring容器在加载FruitServiceImpl这个bean的时候通过这个有参的构造方法去创建实例,之后在这个构造方法中去封装属性Map
// 注意:如果没有指定任何构造方法的话,java会默认提供一个无参的构造方法,但是指定了就不会有默认的构造方法了。
// 参数SailService[],容器会在创建该bean的时候,从spring容器的单例池去获取,如果不存在则会先创建之后在放入单例池中
public FruitServiceImpl(SailService[] sailServices){
for (SailService sailService : sailServices){
String fruitType = sailService.getFruitType();
if (!fruitSailServiceMap.containsKey(fruitType)){
fruitSailServiceMap.put(fruitType, sailService);
}
}
}
@Override
public void sailFruit(Fruit fruit) {
// 根据参数指定的类型,选择对应的销售服务去创建订单
SailService sailService = getSailServie(fruit);
sailService.addOrder(fruit);
}
// 根据类型获取指定的业务处理服务
private SailService getSailServie(Fruit fruit) {
String type = fruit.getType();
return fruitSailServiceMap.get(type);
}
}
4、测试验证
参数传不同的类型
以上完成了通过自定义构造方法,实例化bean的过程。常用于:
1、一个通用接口,有多个实例对象的场景
2、创建bean时封装bean的属性
附:
BeanPostProcessor:
是Spring框架中非常强大的一个接口,它允许开发者在Spring容器创建和初始化Bean的过程中插入自定义的逻辑。亲测会在每一个bean创建的过程中都会被调用一次,因此业务需要梳理清晰,不要做很多无畏的操作。可以在此方法中设置bean的属性,或者配合自定义注解完成一些特俗业务等。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
// bean创建之前执行
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("**Before Initialization****: " + beanName);
return bean; // 返回原bean或修改后的bean
}
// bean创建之后执行
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("**After Initialization****: " + beanName);
return bean; // 返回原bean或修改后的bean
}
}
学海无涯苦作舟!!!