一、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 {@Overridepublic String getFruitType() {return "apple";}@Overridepublic 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 {@Overridepublic String getFruitType() {return "pear";}@Overridepublic 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 {// 所有销售服务的封装Mapprivate 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);}}}@Overridepublic 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创建之前执行 @Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("**Before Initialization****: " + beanName);return bean; // 返回原bean或修改后的bean}// bean创建之后执行 @Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("**After Initialization****: " + beanName);return bean; // 返回原bean或修改后的bean}
}
学海无涯苦作舟!!!