spring父子容器:
为什么会有spring父子容器,,因为一般大一点的项目都是分模块的,,不同的人开发不同的模块,,可以在两个不同的模块中,,使用相同的beanName,,如果不是父子容器,,那么spring的配置文件,后面的会覆盖前面的,,有一个bean就会找不到,,,
要么写成兄弟容器,,两个并列的容器,,通过ctx.setParent()设置一个相同的父容器,,但是,这样不能从其中一个容器,获取到另一个容器的bean,两个容器是相互独立的,,,
所以需要父子容器,,在子容器中,可以获取父容器的Bean,在父容器中不能获取子容器的bean,,,就跟springmvc中一样,
public static void main(String[] args) {// 父子容器ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("merchant_beans.xml");// springmvc中 service中不能注入controller ,,===》 父子容器ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext("consumer_beans.xml");child.setParent(parent);// 重新初始化容器child.refresh();RoleService consumerBean = child.getBean(RoleService.class);merchant.RoleService merchantService = child.getBean(merchant.RoleService.class);}
scope作用域
- singleton : 单例==》 容器启动会直接初始化
- prototype: 多例 ==〉 懒加载,,使用到的时候才会初始化
- request
- session
- application
- websocket
@Bean
@Scope(scopeName = "prototype")User user(){return new User();}
工厂bean
spring整合第三方框架:
- 静态工厂
public class OkHttpClientStaticFactory {public static OkHttpClient getInstance(){OkHttpClient.Builder builder = new OkHttpClient.Builder();builder.setReadTimeout$okhttp(5000);return builder.build();}}
<bean class="com.cj.demo214.OkHttpClientStaticFactory" factory-method="getInstance" id="okHttpClient"/>
- 实例工厂
public class OkHttpClientStaticFactory {private static OkHttpClient okHttpClient;static {OkHttpClient.Builder builder = new OkHttpClient.Builder();builder.setReadTimeout$okhttp(5000);okHttpClient = builder.build();}public static OkHttpClient getInstance(){return okHttpClient;}}
<bean class="com.cj.demo214.OkHttpClientFactory" id="clientFactory"/><bean factory-bean="clientFactory" factory-method="getOkHttpClient" id="okHttpClient2"/>
- FacotryBean : 用的最广泛的,,注入第三方bean
public class OkHttpClientFactoryBean implements FactoryBean<OkHttpClient> {/*** 返回真正的 bean对象* @return* @throws Exception*/@Overridepublic OkHttpClient getObject() throws Exception {OkHttpClient.Builder builder = new OkHttpClient.Builder();return builder.build();}/*** 返回对象的类型* @return*/@Overridepublic Class<?> getObjectType() {return OkHttpClient.class;}/*** 返回false : 只是不是singleton,,, 但不一定是prototype* @return*/@Overridepublic boolean isSingleton() {// 调父类的方法,默认就是truereturn FactoryBean.super.isSingleton();}
}
<!-- 这里向spring注册的是,,这个factoryBean中getObject返回的值--><bean class="com.cj.demo214.OkHttpClientFactoryBean" id="client3"/>
public static void main(String[] args) {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");Object client3 = ctx.getBean("client3");// 获取factoryBean,,前面加上&Object factoryBean = ctx.getBean("&client3");System.out.println("client3.getClass() = " + client3.getClass());System.out.println("factoryBean = " + factoryBean);}
FactoryBean默认是懒加载的,,,,
spring加载配置文件
<!-- 将配置文件中的key-value,,, 注册到spring容器中-->
<context:property-placeholder location="classpath:db.properties"/>
或者使用 @PropertySource("classpath:db.properties")
后置处理器
- BeanPostProcessor : bean的后置处理器,,所有的bean都会执行这个
- BeanFactoryPostProcessor
bean初始化执行的方法:
- 执行设置的
init-method,, - 如果实现了
InitializingBean会执行afterPropertiesSet方法
bean的加载过程:
xml内容 ===〉 BeanDefinition ⇒ 根据beanDefinition的信息实例化bean ===》 给bean的属性赋值(@Autowired @Value等注解注入的值) ===> 调用bean的各种初始化方法 ===》 成品的bean
有两个地方可以对bean修改:
BeanFactoryPostProcessor : bean工厂的后置处理器,,这里会对beanDefinition进行修改,最终影响到生成的bean,,比如说${xxx}占位符,,就是在。BeanFactoryPostProcessor中拦截下来,获取BeanDefinition然后通过visitor ,遍历BeanDefinition并修改其中的属性值。。
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {/*** 只会执行一次,,,, 这个相当于spring容器,,只会执行一次后置处理* 这个时候 BeanDefinition 已经有了,,但是bean还没有生成* @param beanFactory 这个参数相当于 spring容器* @throws BeansException*/@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// beanFactory.getBeanDefinition("")// 获取spring容器中,所有的beanNameString[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();System.out.println(Arrays.toString(beanDefinitionNames));// bean的提前初始化,,,按理说此时bean是没有生成的,,, 这个比spring容器初始化更早
// User user = beanFactory.getBean(User.class);
// System.out.println("user = " + user);BeanDefinition userBeanDefinition = beanFactory.getBeanDefinition("user");//是一个专门用来访问BeanDefinition中属性的工具==》 直接操作 BeanDefinition 比较麻烦,spring中提供了这样一个访问器//BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(strVal -> {// 访问BeanDefinition中所有的值if (strVal.equals("zs")) {return "cc";}return strVal;});// 像 ${xxx} 占位符,,, 就是这样根据 visitor访问 BeanDefinition中的值,,如果发现是 占位符${xxx},, 就将这些占位符替换成spring容器中读取出来的值// 修改userBeanDefinition中的值visitor.visitBeanDefinition(userBeanDefinition);System.out.println("postProcessBeanFactory");}
}
BeanPostProcessor: bean的后置处理器,他起作用的时候,bean已经生成了,,此时就可以对已经生成的bean对象做一些修改,把已经生成的bean拦截下来,做一些修改
public class UserBeanPostProcessor implements BeanPostProcessor {/*** 所有的bean都会执行一边* 初始化之前* @param bean 对象本身* @param beanName 对象的名字* @return* @throws BeansException*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("post process initalization ");if (beanName.equals("user")){User user = (User) bean;user.setUsername("waterkid");return user;}return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}/*** 初始化之后* @param bean* @param beanName* @return* @throws BeansException*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessAfterInitialization");return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}
}
