29 获取ApplicationContext

1 获取ApplicationContext 

Spring工厂的直接获取(两种方式 1 和 2 )

1       //applicationContext.xml 在WEB-INF下
        ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml"); 

2       //applicationContext.xml 在 src下
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

3      //其他方式
        ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(servletContext);  

//容器中获得  
ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(servletContext);  
  
//文件存放绝对路径  
ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");  
  
//工程的classpath;  
//ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

如何选择:
如果applicationContext.xml 在 src下, ClassPathXmlApplication读取
如果applicationContext.xml 在WEB-INF下,FileSystemXmlApplicationContext读取

ApplicationContext直译为应用上下文,是用来加载Spring框架配置文件,来构建Spring的工厂对象,它也称之为Spring容器的上下文对象,也称之为Spring的容器。

ApplicationContext 只是BeanFactory(Bean工厂,Bean就是一个java对象) 一个子接口:

 为什么不直接使用顶层接口对象来操作呢?

ApplicationContext 更加强大, 所以现在开发基本没人使用BeanFactory。

提示:后面还有个FactoryBean,注意区别。

2 bean获取的两种方式(还有其他方式)

常用根据名称获取(id/name)

3 IoC容器装配Bean_基于XML配置方式

实例化Bean的四种方式 (了解)

第一种 无参数构造器 (最常用

//bean的对象就是普通的pojo
public class Bean1 {
	//无参构造方式来实例化bean对象
	
	//如果覆盖了无参构造,那么默认情况下会报错
	private String name;
	/*public Bean1(String name) {
		this.name = name;
	}*/
}

 对应的applicationContext.xml

<!-- 1无参构造:最常用的,底层是spring默认的工厂来实例化对象了 -->
<bean id="bean1" class="cn.itcast.spring.b_newbean.Bean1"/>

第二种 静态工厂方法

//bean的对象就是普通的pojo
public class Bean2 {
    
        ...
        ...
        ...

}
//静态工厂:提供了一个静态方法来实例化bean
public class Bean2Factory {
	
	//该静态方法,用来获取bean2的对象
	public static Bean2 getBean2(){
		//定制自己的工厂:你可以在初始化这个bean的时候,做一些其他的事情(初始化数据库连接、初始化一些依赖的东西)-更灵活
		return new Bean2();
	}

}

  对应的applicationContext.xml

<!-- 2:静态工厂方式获取bean对象:class是工厂的class,不是具体bean的class,
必须指定工厂方法,这种方法配置返回的是该方法返回的bean的对象 -->
<bean id="bean2" class="cn.itcast.spring.b_newbean.Bean2Factory" factory-method="getBean2"/>

第三种 实例工厂方法

//bean的对象就是普通的pojo
public class Bean3 {
    
        ...
        ...
        ...

}
//实例工厂,编写一个普通方法用来初始化bean对象
public class Bean3Factory {
	
	public Bean3 getBean3(){
		//定制工厂:初始化一些数据等
        //这里可以在new Bean3之前做很多逻辑判断
        //比如判断new 哪个子对象
		return new Bean3();
	}

}

   对应的applicationContext.xml

<!-- 3:实例工厂来获取bean对象:必须先实例化工厂,然后再配置方法 -->
<bean id="bean3Factory" class="cn.itcast.spring.b_newbean.Bean3Factory"/>
<!--factory-bean相当于前面的ref,要写实例工厂bean的名字  -->
<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>

第四种:FactoryBean方式。(源码底层用的多)

//bean的对象就是普通的pojo
public class Bean4 {
    
        ...
        ...
        ...

}
//工厂bean的方式实例化bean,泛型就是要实例化的对象类型
public class Bean4FactoryBean implements FactoryBean<Bean4>{

	@Override
	//获取实例化对象,配置bean,得到的对象就从这里来的
	public Bean4 getObject() throws Exception {
		//初始化一些其他数据
		return new Bean4();//返回了具体的bean对象
	}

	@Override
	public Class<?> getObjectType() {
		return null;
	}

	@Override
	public boolean isSingleton() {
		return false;
	}


}

    对应的applicationContext.xml

<!-- 4工厂bean的方式:spring会自动调用该接口的getObject来获取具体的对象 -->
<bean id="bean4" class="cn.itcast.spring.b_newbean.Bean4FactoryBean"/>

小总结: 

 完整applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:p="http://www.springframework.org/schema/p"
       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">

	<!-- 快速入门 -->
	<!-- ioc(控制反转-将对象的创建的权利从类型本身来创建,来交给spring工厂来创建)的配置 -->
	<!-- 
	<bean>:豆子,spring中bean可以认为是个对象。
	class:是实现类的全名,spring工厂会自动根据该类型名字,采用反射机制来得到具体的类的类型
	id:bean的名称(对象的名称),作用是:是在应用程序中,得到对象的标识,注意:id在整个spring的配置文件中,必须唯一!
	习惯上,id的名字会使用接口的名字小写
	name:作用同id,可通用!
	 -->
	<bean id="userDAO" class="cn.itcast.spring.a_quickstart.dao.UserDAOImpl"></bean>
	<!-- 将service也交给spring管理(new) -->
	<bean id="userService" class="cn.itcast.spring.a_quickstart.service.UserServiceImpl">
		<!-- 将userDAO的bean注入给userSErvice ,依赖关系,在这里维护-->
		<!-- 
		name:UserServiceImpl类中被注入对象的setter的名字:例如:setXxx,名字xxx(小写的)
		ref:要注入的具体bean对象的引用,写被依赖的bean的名字
		 -->
		<property name="userDAO" ref="userDAO"/>
	</bean>
	
	<!-- bean的构造 -->
	<!-- 1无参构造:最常用的,底层是spring默认的工厂来实例化对象了 -->
	<bean id="bean1" class="cn.itcast.spring.b_newbean.Bean1"/>
	<!-- 2:静态工厂方式获取bean对象:class是工厂的class,不是具体bean的class,必须指定工厂方法,这种方法配置返回的是该方法返回的bean的对象 -->
	<bean id="bean2" class="cn.itcast.spring.b_newbean.Bean2Factory" factory-method="getBean2"/>
	<!-- 3:实例工厂来获取bean对象:必须先实例化工厂,然后再配置方法 -->
	<bean id="bean3Factory" class="cn.itcast.spring.b_newbean.Bean3Factory"/>
	<!--factory-bean相当于前面的ref,要写实例工厂bean的名字  -->
	<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>
	<!-- 4工厂bean的方式:spring会自动调用该接口的getObject来获取具体的对象 -->
	<bean id="bean4" class="cn.itcast.spring.b_newbean.Bean4FactoryBean"/>

	<!-- bean的作用域 -->
	<!-- 单例 :scope可以省略,默认值-->
	<!-- <bean id="singletonBean" class="cn.itcast.spring.c_scope.SingletonBean" scope="singleton"></bean> -->
	<!-- 多例 -->
	<!-- <bean id="prototypeBean" class="cn.itcast.spring.c_scope.PrototypeBean" scope="prototype"></bean> -->
	<!-- bean的生命周期 -->
	<!-- <bean id="lifeRecycleBean" class="cn.itcast.spring.d_liferecycle.LifeRecycleBean" 
	init-method="initBean" destroy-method="destroyBean" scope="prototype"/> -->
	
	<!-- bean后处理器 -->
	<!-- <bean class="cn.itcast.spring.d_liferecycle.MyBeanPostProcessor"/> -->
	
	<!-- 注入 -->
	<!-- 构造器的注入 -->
	<bean id="car" class="cn.itcast.spring.e_di.Car">
		<!-- 
		<constructor-arg :进行构造器注入,注意,Car类,中必须有对应的构造方法!
		两类:
		1类:指定用哪个参数来赋值
		index:使用索引定位哪个参数
		name:使用参数名来定位
		type:使用数据类型来定位哪个参数
		2类:赋具体什么值
		value:简单数据类型,字符串,数字等。
		ref:复杂类型,主要就是只bean对象,值要写bean的名字。
		 -->
		<!-- <constructor-arg index="0" value="1001"/> -->
		<!-- <constructor-arg name="name" value="凯迪拉克"/> -->
		<constructor-arg type="java.lang.Double" value="99999999d"/>
		<!-- 补充:定位方式可混合使用 -->
		<constructor-arg index="0" name="id" value="1001"/>
		<!-- 补充:属性的写法:可以写成子元素 -->
		<constructor-arg name="name" >
			<value>凯迪拉克</value>
		</constructor-arg>
	</bean>
	<!-- setter属性注入 -->
	<bean id="person" class="cn.itcast.spring.e_di.Person">
		<!-- 
		<property代表setter属性注入
		name:setter的名字,setXxx,名字xxx,注意大小写
		value:简单类型数据
		ref:bean的名字,可以注入一个bean对象,car是由spring帮你new好了的。
		 -->
		<property name="name" value="Rose"/>
		<!-- <property name="car" ref="car"/> -->
		<!-- 补充:成员变量的名字可以和setter方法的名字不一致 -->
		<!-- 补充:元素写法问题,赋值属性,可以写成子元素,使用很少 -->
		<property name="car" >
			<ref bean="car"/>
		</property>
	</bean>
	<!-- p的名称空间
	p:name相当于<property name="name" value="Rose"/>
	p:car-ref:相当于: <property name="car" ref="car"/>
	 -->
	<bean id="person2" class="cn.itcast.spring.e_di.Person" p:name="Jack" p:car-ref="car"/>
	<!-- spEL表达式 -->
	<!-- <bean id="person3" class="cn.itcast.spring.e_di.Person" p:name="#{'Jack'.toUpperCase()}" p:car="#{car}"/> -->
	<!-- 
	#{car.name}相当于car.getName()
	 -->
	<bean id="person3" class="cn.itcast.spring.e_di.Person" p:name="#{car.name}" p:car="#{car}"/>
	
	<!-- 集合属性的注入 -->
	<bean id="collectionBean" class="cn.itcast.spring.e_di.CollectionBean">
		<!-- list的属性注入 -->
		<property name="list" >
			<list>
				<value>qqq</value>
				<value>www</value>
				<!-- <ref/> -->
			</list>
		</property>
		<!-- set属性 -->
		<property name="set">
			<set>
				<value>1</value>
				<value>2</value>
			</set>
		</property>
		<!-- map属性注入 -->
		<property name="map">
			<map>
				<entry key="q" value="w"></entry>
				<entry key="a" value="s"></entry>
			</map>
		</property>
		<!-- properties属性注入 -->
		<property name="properties">
			<props>
				<prop key="name1">value1</prop>
				<prop key="name2">value2</prop>
			</props>
		</property>
	</bean>
	
</beans>

【面试题】 BeanFactory和FactoryBean的区别?

BeanFactory:是一个工厂(其实是构建了一个spring上下文的环境,容器),用来管理和获取很多Bean对象,

FactoryBean:是一个Bean生成工具,是用来获取一种类型对象的Bean,它是构造Bean实例的一种方式。

Bean的作用域

项目开发中通常会使用:singleton 单例、 prototype多例

Singleton: 在一个spring容器中,对象只有一个实例。(默认值)

Prototype: 在一个spring容器中,存在多个实例,每次getBean 返回一个新的实例

//单例Bean
public class SingletonBean {
	//在默认的构造器中打打印一句
	public SingletonBean() {
		System.out.println("初始化了SingletonBean");
	}
}
//多例Bean
public class PrototypeBean {
	public PrototypeBean() {
		System.out.println("初始化了PrototypeBean");
	}
}
	@Test
	public void test(){
		//得到工厂
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		//得到bean
		//单例
		//单例的情况下,在容器初始化的时候,bean就已经被初始化了
		SingletonBean singletonBean=(SingletonBean) applicationContext.getBean("singletonBean");
		System.out.println(singletonBean);
		SingletonBean singletonBean2=(SingletonBean) applicationContext.getBean("singletonBean");
		System.out.println(singletonBean2);
		// 补充:根据类型来获取bean如果类型相同,那么就无法获取这个bean
		SingletonBean singletonBean3=(SingletonBean) applicationContext.getBean(SingletonBean.class);
		System.out.println(singletonBean3);

		//多例
		//在多例的情况下,容器初始化的时候,不初始化bean,只有在getBean(获取的)的时候才初始化该bean,而且每次getbean都会初始化一个不同的bean对象
		PrototypeBean prototypeBean=(PrototypeBean) applicationContext.getBean("prototypeBean");
		System.out.println(prototypeBean);
		PrototypeBean prototypeBean2=(PrototypeBean) applicationContext.getBean("prototypeBean");
		System.out.println(prototypeBean2);
	}

测试结果: 

【注意】

单例是默认值,如果需要单例对象,则不需要配置scope。

@Scope("prototype")  

关于@Scope注解的用法:

Controller 是单例还是多例?怎么保证并发的安全_╱℡❄&▓的博客-CSDN博客

5 在xml配置Bean的初始化和销毁方法

通过 init-method属性 指定初始化的方法

通过 destroy-method属性 指定销毁对象的方法

//声明周期测试
public class LifeRecycleBean {
	
    //
	public LifeRecycleBean() {
		System.out.println("LifeRecycleBean构造方法");
	}
	
	//
	public void initBean(){
		System.out.println("LifeRecycleBean初始化");
	}
	
	//
	public void destroyBean(){
		System.out.println("LifeRecycleBean销毁");
	}

}
package cn.itcast.spring.d_liferecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor{
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		if(beanName.equals("lifeRecycleBean")){
			System.out.println("");
		}
		return bean;//
		
		//return null;//
	}
	@Override
	//
	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		System.out.println("");
		return bean;
	}

}

 配置:

正确的测试代码: 

    @Test
	public void test(){
		//Sping工厂、spring上下文、spring容器
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		//bean在初始化之后(先调用构造),才调用init方法
		//构造方法和init方法一般用来初始化一些属性、需要提前准备的数据等
		LifeRecycleBean lifeRecycleBean=(LifeRecycleBean) applicationContext.getBean("lifeRecycleBean");
		System.out.println(lifeRecycleBean);

		// 为什么没有销毁方法?原因是:调试结束时,自动强行关闭jdk,容器根本来不及自己关闭,被jdk自动GC
		//
		// 如果想看这个方法,需要手动关闭spring容器
		//
		//如果是多例,则默认情况下无法调用销毁方法,多例没有强制销毁。
		((ClassPathXmlApplicationContext)applicationContext).close();
	}

6 后处理Bean(BeanPostProcessor接口)

后处理Bean也称之为Bean的后处理器,作用是:在Bean初始化前后,对Bean对象进行增强的。它既可以增强一个指定的Bean,也可以增强所有的Bean,底层很多功能(如AOP等)的实现都是基于它的,Spring可以在容器中直接识别调用。 

执行任意bean操作的测试,控制台输出: 

BeanPostProcessor接口,提供增强途径,在不修改原来代码情况下,增添新的功能! 

7 Bean属性的依赖注入 

什么是Bean属性的注入?就是对一个对象的属性赋值。有三种方式:

  1. 第一种:构造器参数注入
  2. 第二种:setter方法属性注入(setter方法的规范-JavaBean规范)
  3. 第三种:接口注入

Spring 框架规范中通过配置文件配置的方式,只支持构造器参数注入和setter方法属性注入,不支持接口注入 !

构造器参数注入属性值

 

setter方法属性注入 property 

两步:在类中加入setter方法,在配置文件中使用property

 

p名称空间的使用 

什么是名称空间?

作用:Schema区分同名元素。(有点类似于java的包)

回顾:Xmlns没有前缀是默认的名称空间。

为简化XML文件的配置,Spring2.5版本开始引入了一个新的p名称空间。简单的说,它的作用是为了简化setter方法属性依赖注入配置的,它不是真正的名称空间。

它的使用方法:

 

 1) 引入p名称空间

<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:p="http://www.springframework.org/schema/p"
       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">

2) 将<property> 子元素 简化为 元素的属性

 配置时不需要<property > 子元素,简化了配置 .

spEL表达式的使用

spEL(Spring Expression Language)是一种表达式语言,它是spring3.x版本的新特性。 

它的作用是:支持在运行时操作和查询对象,其语法类似统一的EL语言,但是SpEL提供了额外的功能,功能更强大。

语法: #{…} , 引用另一个Bean 、属性、 方法

SpEL表达式的使用功能比较多,Bean操作相关的通常有:

  1. #{beanid} 引用Bean(具体对象)
  2. #{beanId.属性} 引用Bean的属性
  3. #{beanId.方法(参数)} 调用Bean的方法

 集合类型属性注入

 作用:主要用于框架整合配置

 

Spring为集合提供了对应的标签:

<list> 注入 list元素

<set> 注入 set元素

<map> 注入 map元素

<props> 注入 properties 元素 (hashtable类的子类,是特殊的map,key和value都是String )

 

 

 

7 IoC容器装配Bean_基于注解配置方式

Bean的定义(注册) -- 扫描机制

新建web项目:spring3_day1_annotation

第一步:导入jar包,log4j.properties,applicationContext.xml

Spring XML开发和注解开发 导入jar包是相同的

第二步: 编写Service和DAO 的注册

  xml做法 : <bean id=”customerService” class=”…” />

注解做法 : spring2.5引入 @Component 注解

 

 第三步: 配置注解Bean的扫描。配置的示例如下:

 引入context 名称空间 :

【注意】Spring的所有名称空间都需要基于Beans的名称空间。

引入后:

<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.xsd">

核心配置文件中开启注解功能和配置扫描注解Bean的位置

 <context:componet-scan> 具有 <context:annotation-config> 作用 !

 

实际开发中,使用的是@Component三个衍生注解(“子注解”)

子注解的作用:有分层的意义(分层注解)。

 

 

 Bean属性的依赖注入

简单数据类型依赖注入

 复杂类型数据依赖注入

注解实现属性依赖注入,将注解加在setXxx方法上 或者 属性定义上 !(任选其一,省代码了)

第一种: 使用@Value 结合SpEL  ---- spring3.0 后用

第二种:使用@Autowired 结合 @Qualifier

单独使用@Autowired 按照类型注入

 使用@Autowired + @ Qualifier 按照名称注入

 第三种: JSR-250标准(jdk) 提供@Resource

 

第四种: JSR-330标准(jdk) 提供 @Inject (麻烦点)

需要先导入 javax.inject 的 jar

按照类型注入

 按照名称注入

Bean的初始化和销毁

使用 @PostConstruct 注解, 标明初始化方法 ---相当于 init-method 指定初始化方法

使用 @PreDestroy 注解, 标明销毁方法  ----相当于 destroy-method 指定对象销毁方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值