1 Spring框架Bean实例化的方式:
提供了三种方式实例化Bean.
- 构造方法实例化:(默认无参数)
- 静态工厂实例化:
- 实例工厂实例化:
无参数构造方法的实例化:
<!-- 默认情况下使用的就是无参数的构造方法. -->
<bean id="bean1" class="cn.itcast.spring3.demo2.Bean1"></bean>
静态工厂实例化:
<!-- 第二种使用静态工厂实例化 -->
<bean id="bean2" class="cn.itcast.spring3.demo2.Bean2Factory" factory-method="getBean2"></bean>
需要写两个类一个是实例化的类bean2,另外一个是实例化类的工厂Bean2Factory,这个实例方法必须要是静态的,通过这个方法就实例化这个bean2了
public class Bean2Factory {
public static Bean2 getBean2(){
System.out.println("静态工厂的获得Bean2的方法...");
return new Bean2();
}
}
实例工厂实例化:
<!-- 第三种使用实例工厂实例化 -->
<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>
<bean id="bean3Factory" class="cn.itcast.spring3.demo2.Bean3Factory"/>
这个是表示首先需要实例化工厂,然后指定需要实例的对象bean3,并给他指定实例化他的类和实例化他的方法
public class Bean3Factory {
public Bean3 getBean3(){
System.out.println("Bean3实例工厂的getBean3方法...");
return new Bean3();
}
}
注意:以上三种实例化方法我们主要是使用第一种利用无参构造函数来实例化一个对象,所以在写类的时候最好加一个无参的构造函数
2 Bean的其他配置:
(1) id和name的区别:
- id遵守XML约束的id的约束.id约束保证这个属性的值是唯一的,而且必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号
- name没有这些要求
- 注意:
- 如果bean标签上没有配置id,那么name可以作为id.
- 开发中Spring和Struts1整合的时候, /login.这种不能作为id只能作为name了。
- 现在的开发中都使用id属性即可.
(2) 类的作用范围:
scope属性 :
- singleton :单例的.(默认的值.)
- prototype :多例的.
- request :web开发中.创建了一个对象,将这个对象存入request范围,request.setAttribute();
- session :web开发中.创建了一个对象,将这个对象存入session范围,session.setAttribute();
- globalSession :一般用于Porlet应用环境.指的是分布式开发.不是porlet环境,globalSession等同于session;
实际开发中主要使用singleton,prototype
(3) Bean的生命周期:
- 配置Bean的初始化和销毁的方法:
- 配置初始化和销毁的方法:
* init-method=”setup”
* destroy-method=”teardown”
- 执行销毁的时候,必须手动关闭工厂,而且只对scope=”singleton”有效.
<bean id="helloService" class="HelloService" init-method="setup" destroy-method="teardown"/>
也就是说在实例化这个对象的时候指定了初始化的方法就是setup,而销毁的方法是teardown,初始化是指在构造器结束之后也就是对象实例化之后先执行的方法,而销毁方法是指对象销毁的时候执行的方法,通常我们可以通过classPathXmlApplicationContext.close();
来实现对象的销毁。
Bean的生命周期的11个步骤:
- instantiate bean对象实例化
- populate properties 封装属性
- 如果Bean实现BeanNameAware 执行 setBeanName
- 如果Bean实现BeanFactoryAware 或者 ApplicationContextAware 设置工厂 setBeanFactory 或者上下文对象 setApplicationContext
- 如果存在类实现 BeanPostProcessor(后处理Bean) ,执行postProcessBeforeInitialization
- 如果Bean实现InitializingBean 执行 afterPropertiesSet
- 调用 指定初始化方法 init
- 如果存在类实现 BeanPostProcessor(处理Bean) ,执行postProcessAfterInitialization
- 执行业务处理
- 如果Bean实现 DisposableBean 执行 destroy
- 调用 指定销毁方法 customerDestroy
观察生命周期
public class CustomerServiceImpl implements CustomerService, BeanNameAware,ApplicationContextAware,InitializingBean,DisposableBean {
private String name;
public void setName(String name) {
System.out.println("第二步:属性的注入.");
this.name = name;
}
public CustomerServiceImpl() {
super();
System.out.println("第一步:实例化类.");
}
public void add(){
System.out.println("添加客户...");
}
public void find(){
System.out.println("查询客户...");
}
public void setBeanName(String name) {
System.out.println("第三步:注入配置的类的名称"+name);
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
System.out.println("第四步:注入applicationContext"+applicationContext);
}
public void afterPropertiesSet() throws Exception {
System.out.println("第六步:属性设置后执行...");
}
public void setup(){
System.out.println("第七步:调用手动设置的初始化方法...");
}
public void destroy() throws Exception {
System.out.println("第十步:调用销毁的方法...");
}
public void teardown(){
System.out.println("第十一步:调用手动销毁方法...");
}
}
存在一个类实现BeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor{
/**
* bean:实例对象
* beanName:在配置文件中配置的类的标识.
*/
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("第五步:初始化之前执行...");
return bean;
}
public Object postProcessAfterInitialization(final Object bean, String beanName)
throws BeansException {
System.out.println("第八步:初始化后执行...");
// 动态代理:
if(beanName.equals("customerService")){
Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces() , new InvocationHandler() {
// 调用目标方法的时候,调用invoke方法.
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("add".equals(method.getName())){
System.out.println("权限校验...");
Object result = method.invoke(bean, args);
//System.out.println(System.currentTimeMillis());
return result;
}
return method.invoke(bean, args);
}
});
return proxy;
}
return bean;
}
}
配置
<!-- demo4Bean的生命周期==================================== -->
<bean id="customerService" class="cn.itcast.spring3.demo4.CustomerServiceImpl" init-method="setup" destroy-method="teardown">
<property name="name" value="itcast"></property>
</bean>
<bean class="cn.itcast.spring3.demo4.MyBeanPostProcessor"></bean>
一旦配置文件里有类实现了BeanPostProcessor,那么配置文件中的所有类实例化的时候都需要去执行这个类里面的先处理bean和后处理bean的两个方法,所以是否配置这个是需要考虑的,它主要用处也可以在权限校验的时候作用比较明显。
在CustomerService类的add方法之前进行权限校验?
3 Bean中属性注入:
Spring支持构造方法注入和setter方法注入:
构造器注入:
这里面通过构造注入需要在写一个带参数的构造器,但是无参的构造器也要有,否则不能实例化类了,如果出入的属性只是一般属性那么用value传值就可以了,name属性主要指定传给哪一个属性,当然也可以通过index来指定给第几个参数传值,也可以指定参数的类型type,这个是可选的。
<bean id="car" class="cn.itcast.spring3.demo5.Car">
<!-- <constructor-arg name="name" value="宝马"/>
<constructor-arg name="price" value="1000000"/> -->
<constructor-arg index="0" type="java.lang.String" value="奔驰"/>
<constructor-arg index="1" type="java.lang.Double" value="2000000"/>
</bean>
setter方法注入:
注意这里面通过setter方式意思就是实例化类里面需要让属性有setXXX方法才能够注入进去否则不行
<bean id="car2" class="cn.itcast.spring3.demo5.Car2">
<!-- <property>标签中name就是属性名称,value是普通属性的值,ref:引用其他的对象 -->
<property name="name" value="保时捷"/>
<property name="price" value="5000000"/>
</bean>
setter方法注入对象属性:
<property name="car2" ref="car2"/>
名称空间p:注入属性(一般不用):
Spring2.5版本引入了名称空间p.
p:<属性名>="xxx" 引入常量值
p:<属性名>-ref="xxx" 引用其它Bean对象
引入名称空间:
<beans xmlns="http://www.springframework.org/schema/beans"
<font color=red> xmlns:p="http://www.springframework.org/schema/p"</font>
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="car2" class="cn.itcast.spring3.demo5.Car2" p:name="宝马" p:price="400000"/>
<bean id="person" class="cn.itcast.spring3.demo5.Person" p:name="童童" p:car2-ref="car2"/>
SpEL:属性的注入(我觉得也一般不用):
Spring3.0提供注入属性方式:
语法:#{表达式}
- 注意这里面我们注入属性的话就全部用value,如果是普通属性就用‘’,如果是引用其他对象就直接将该对象的id加进来就可以了,同时还可以注入其他对象的属性或者方法的值。
<bean id="car2" class="cn.itcast.spring3.demo5.Car2">
<property name="name" value="#{'大众'}"></property>
<property name="price" value="#{'120000'}"></property>
</bean>
<bean id="person" class="cn.itcast.spring3.demo5.Person">
<!--<property name="name" value="#{personInfo.name}"/>-->
<property name="name" value="#{personInfo.showName()}"/>
<property name="car2" value="#{car2}"/>
</bean>
<bean id="personInfo" class="cn.itcast.spring3.demo5.PersonInfo">
<property name="name" value="张三"/>
</bean>
4 集合属性的注入:
<bean id="collectionBean" class="cn.itcast.spring3.demo6.CollectionBean">
<!-- 注入List集合 -->
<property name="list">
<list>
<value>童童</value>
<value>小凤</value>
</list>
</property>
<!-- 注入set集合 -->
<property name="set">
<set>
<value>杜宏</value>
<value>如花</value>
</set>
</property>
<!-- 注入map集合 -->
<property name="map">
<map>
<entry key="刚刚" value="111"/>
<entry key="娇娇" value="333"/>
</map>
</property>
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">123</prop>
</props>
</property>
</bean>
实例化的类
public class CollectionBean {
private List<String> list;
private Set<String> set;
private Map<String,Integer> map;
private Properties properties;
public void setSet(Set<String> set) {
this.set = set;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, Integer> map) {
this.map = map;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "CollectionBean [list=" + list + ", set=" + set + ", map=" + map
+ ", properties=" + properties + "]";
}
}
5加载配置文件:
如果配置文件过多或者为了保证不让一个配置文件内容太多可以分开写,那么在加载的时候是可以通过这两种方式加载多个配置文件的,其中第二种方式是在某个配置文件中拼接另外一个配置文件。
一种写法:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml",”bean2.xml”);
二种方法:
<import resource="applicationContext2.xml"/>