目录
一、 列举一些创建对象有哪几种方式
二、自定义BeanPostProcess生成代理对象
1、实战案例
2、源码分析
三、通过supplier创建对象
1、实战案例
2、源码分析
四、通过FactoryMethod创建对象
1、实战案例
2、源码分析
五、小总结
一、 列举一些创建对象有哪几种方式
这篇文章我们主要聊聊BeanPostProcess、Supplier、FactoryMethod这三种方式是怎么创建对象,
至于FactoryBean前面已经介绍到,反射的话不说了,自行解决
二、自定义BeanPostProcess生成代理对象
1、实战案例
先上案例,通过现象,挖掘本质,
mian测试方法如下:
public class ResolveBeforeInstantiationTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("resolvebeforeinstantiation.xml");
BeforeInstantiation bean = ac.getBean(BeforeInstantiation.class);
bean.doSomeThing();
}
}
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="beforeInstantiation" class="com.yang.test.resolvebeforeinstantiation.BeforeInstantiation"></bean>
<bean id="myInstantiationAwareBeanPostProcessor" class="com.yang.test.resolvebeforeinstantiation.MyInstantiationAwareBeanPostProcessor"></bean>
</beans>
BeanPostProcessor方法如下:
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("beanName:"+beanName+"----执行postProcessBeforeInstantiation方法");
if (beanClass == BeforeInstantiation.class){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanClass);
enhancer.setCallback(new MyMethodInterceptor());
BeforeInstantiation beforeInstantiation = (BeforeInstantiation) enhancer.create();
System.out.println("创建代理对象:"+beforeInstantiation);
return new BeforeInstantiation();
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("beanName:"+beanName+"----执行postProcessAfterInstantiation方法");
return false;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("beanName:"+beanName+"----执行postProcessBeforeInitialization方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("beanName:"+beanName+"----执行postProcessAfterInitialization方法");
return bean;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
System.out.println("beanName:"+beanName+"----执行postProcessProperties方法");
return pvs;
}
}
代理方法如下:
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("目标方法执行之前:" + method);
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("目标方法执行之后:" + method);
return o1;
}
}
真实类如下:
public class BeforeInstantiation {
public void doSomeThing(){
System.out.println("执行do some thing....");
}
}
运行结果如下:
2、源码分析
大家有没有想过他是怎么执行到 postProcessBeforeInstantiation方法的呢?
来!上源码,下面只列举关键代码,至于流程,还是需要自己去debug过才最清楚,因为学源码不debug,单纯看=白学
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
// 如果beforeInstantiationResolved值为null或者true,那么表示尚未被处理,进行后续的处理
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
// 确认beanclass确实在此处进行处理
// 判断当前mbd是否是合成的,只有在实现aop的时候synthetic的值才为true,并且是否实现了InstantiationAwareBeanPostProcessor接口
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 是否解析了
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
resolveBeforeInstantiation在createBean方法里面调用
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
// 锁定class,根据设置的class属性或者根据className来解析class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
// 验证及准备覆盖的方法,lookup-method replace-method,当需要创建的bean对象中包含了lookup-method和replace-method标签的时候,会产生覆盖操作
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 给BeanPostProcessors一个机会来返回代理来替代真正的实例,应用实例化前的前置处理器,用户自定义动态代理的方式,针对于当前的被代理类需要经过标准的代理流程来创建对象
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 真正干活的方法doCreateBean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
三、通过supplier创建对象
1、实战案例
测试类
public class TestSupplier {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("supplier.xml");
User bean = ac.getBean(User.class);
System.out.println(bean.getUsername());
}
}
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="user" class="com.yang.test.supplier.User"></bean>
<bean class="com.yang.test.supplier.SupplierBeanFactoryPostProcessor"></bean>
</beans>
SupplierBeanFactoryPostProcessor类:
public class SupplierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 这个没有意义,只不过有这么一种创建bean的方式,实际上配了xml正常流程都会创建user 的bean
BeanDefinition user = beanFactory.getBeanDefinition("user");
GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) user;
genericBeanDefinition.setInstanceSupplier(CreateSupplier::createUser);
genericBeanDefinition.setBeanClass(User.class);
}
}
CreateSupplier类
public class CreateSupplier {
public static User createUser(){
return new User("zhangsan");
}
}
2、源码分析
关键源码位置:
从BFPP已经实例化了
/**
* Invoke the given BeanFactoryPostProcessor beans.
*/
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
.tag("postProcessor", postProcessor::toString);
postProcessor.postProcessBeanFactory(beanFactory);
postProcessBeanFactory.end();
}
}
在createBeanInstance方法里面调用
// 判断当前beanDefinition中是否包含实例供应器,此处相当于一个回调方法,利用回调方法来创建bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
四、通过FactoryMethod创建对象
1、实战案例
Person.java
public class Person {
private int id;
private String name;
private int age;
private String gender;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
PersonInstanceFactory.java
public class PersonInstanceFactory {
public Person getPerson(String name){
Person person = new Person();
person.setId(1);
person.setName(name);
return person;
}
}
PersonStaticFactory.java
public class PersonStaticFactory {
public static Person getPerson(String name){
Person person = new Person();
person.setId(1);
person.setName(name);
return person;
}
}
factoryMethod.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="person5" class="com.mashibing.factoryMethod.PersonStaticFactory" factory-method="getPerson">
<!--constructor-arg:可以为方法指定参数-->
<constructor-arg value="lisi"></constructor-arg>
</bean>
<bean id="personInstanceFactory" class="com.mashibing.factoryMethod.PersonInstanceFactory"></bean>
<!--
factory-bean:指定使用哪个工厂实例
factory-method:指定使用哪个工厂实例的方法
-->
<bean id="person6" class="com.mashibing.factoryMethod.Person" factory-bean="personInstanceFactory" factory-method="getPerson">
<constructor-arg value="wangwu"></constructor-arg>
</bean>
</beans>
Test.java
public class Test {
public static void main(String[] args) {
MyClassPathXmlApplicationContext ac = new MyClassPathXmlApplicationContext("factoryMethod.xml");
}
}
2、源码分析
关键位置:
createBeanInstance方法里面
// 如果工厂方法不为空则使用工厂方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
五、小总结
debug的话,永远要记住这个流程,很关键