Spring入门到进阶 - Spring Bean管理 XML方式
Posted GreyBig
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring入门到进阶 - Spring Bean管理 XML方式相关的知识,希望对你有一定的参考价值。
Spring的工厂类介绍
public class SpringDemo1 {
@Test
/**
* 传统方式开发
*/
public void demo1(){
// UserService userService = new UserServiceImpl();
UserServiceImpl userService = new UserServiceImpl();
// 设置属性:
userService.setName("张三");
userService.sayHello();
}
@Test
/**
* Spring的方式实现
*/
public void demo2(){
// 创建Spring的工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类:
UserService userService = (UserService) applicationContext.getBean("userService");
userService.sayHello();
}
@Test
/**
* 读取磁盘系统中的配置文件
*/
public void demo3(){
// 创建Spring的工厂类:
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("c:\applicationContext.xml");
// 通过工厂获得类:
UserService userService = (UserService) applicationContext.getBean("userService");
userService.sayHello();
}
@Test
/**
* 传统方式的工厂类:BeanFactory
*/
public void demo4(){
// 创建工厂类:
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
// 通过工厂获得类:
UserService userService = (UserService) beanFactory.getBean("userService");
userService.sayHello();
}
/**
* 传统方式的工厂类:BeanFactory
*/
@Test
public void demo5(){
// 创建工厂类:
BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("c:\applicationContext.xml"));
// 通过工厂获得类:
UserService userService = (UserService) beanFactory.getBean("userService");
userService.sayHello();
}
}
resources/applicationContext.xml
<!-- UserService的创建权交给了Spring -->
<bean id="userService" class="com.imooc.ioc.demo1.UserServiceImpl">
<property name="name" value="李四"/>
</bean>
Bean的实例化三种方式
resources/applicationContext.xml
<!--Bean的实例化的三种方式============================-->
<!--第一种:无参构造器的方式-->
<bean id="bean1" class="com.imooc.ioc.demo2.Bean1"/>
<!--第二种:静态工厂的方式-->
<bean id="bean2" class="com.imooc.ioc.demo2.Bean2Factory" factory-method="createBean2"/>
<!--第三种:实例工厂的方式-->
<bean id="bean3Factory" class="com.imooc.ioc.demo2.Bean3Factory"/>
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"/>
1、采用无参数的构造方法的方式
public class Bean1 {
public Bean1(){
System.out.println("Bean1被实例化了...");
}
}
@Test
public void demo1(){
// 创建工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类的实例:
Bean1 bean1 = (Bean1)applicationContext.getBean("bean1");
}
2、静态工厂实例化方式
public class Bean2 {
}
// Bean2的静态工厂
public class Bean2Factory {
public static Bean2 createBean2(){
System.out.println("Bean2Factory的方法已经执行了...");
return new Bean2();
}
}
@Test
public void demo2(){
// 创建工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类的实例:
Bean2 bean2 = (Bean2)applicationContext.getBean("bean2");
}
3、实例工厂实例化
public class Bean3 {
}
// Bean3的实例工厂
public class Bean3Factory {
public Bean3 createBean3(){
System.out.println("Bean3Factory执行了...");
return new Bean3();
}
}
@Test
public void demo3(){
// 创建工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类的实例:
Bean3 bean3 = (Bean3)applicationContext.getBean("bean3");
}
Bean的常用配置
1、一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称,id属性在IOC容易中必须是唯一的,如果Bean的名称中含有特殊字符,就需要使用name属性
2、class用于设置一个类的完全路径名称,主要作用是IOC容器生成类的实例
Bean的作用域(scope属性):
1、singleton(默认值)在SpringIOC容器中仅存在一个Bean实例,Bean以单实例的方式存在;
2、prototype:每次调用getBean()时都会返回一个新的实例;
3、request:每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境;
4、session:同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean。该作用域仅适用于WebApplicationContext环境
Spring容器中Bean的生命周期
Spring初始化bean或销毁bean时,有时需要做一些处理工作,因此Spring可以在创建和销毁bean的时候调用bean的两个生命周期方法
<bean id="abc" class="com.imooc.hello"
init-method="init"
destory-method="destory"
/>
当bean被载入到容器的时候调用init,当bean从容器中删除的时候调用destory(scope=singleton有效)
Bean的生命周期的完整过程
- instantiate bean对象实例化
- populate properties 封装属性
- 如果Bean实现BeanNameAware执行setBeanName
- 如果Bean实现BeanFactoryAware或者ApplicationContextAware 设置工厂
setBeanFactory或者上下文对象setApplicationContext - 如果存在类实现BeanPostProcessor (后处理Bean) , 执行postProcessBeforeInitialization
- 如果Bean实现InitializingBean执行afterPropertiesSet
- 调用< bean init-method= "init">指定初始化方法init
- 如果存在类实现BeanPostProcessor (处理Bean),执行
postProcessAfterInitialization - 执行业务处理
- 如果Bean实现DisposableBean执行destroy
- s调用< bean destroy-method= "customerDestroy">指定销毁方法
customerDestroy
BeanPostProcessor的作用
resources/applicationContext.xml
<bean class="com.imooc.ioc.demo3.MyBeanPostProcessor"/>
<bean id="userDao" class="com.imooc.ioc.demo3.UserDaoImpl"/>
public class UserDaoImpl implements UserDao {
@Override
public void findAll() {
System.out.println("查询用户。。。");
}
@Override
public void save() {
System.out.println("保存用户。。。");
}
@Override
public void update() {
System.out.println("修改用户。。。");
}
@Override
public void delete() {
System.out.println("删除用户。。。");
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//System.out.println("第五步:初始化前方法...");
return bean;
}
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
//System.out.println("第八步:初始化后方法...");
if ("userDao".equals(beanName)) {
Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("save".equals(method.getName())) {
System.out.println("权限校验===================");
return method.invoke(bean, args);
}
return method.invoke(bean, args);
}
});
return proxy;
} else {
return bean;
}
}
}
@Test
public void demo2(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Man man = (Man)applicationContext.getBean("man");
man.run();
applicationContext.close();
}
结果:
1、第一个proxy是Proxy.newProxyInstance得到的实例。而第二个proxy是InvocationHandler中的invoke方法的参数名。
2、这里的method属性传入的是Method类的对象,并不是一个名字。这个method对象是用真正的方法名,由方法名和形参抽象出Method对象。
3、args[]中传入的是原方法执行所需要的参数,由于参数可能有多个,所以使用数组。
4、这里不能返回this,invoke方法的返回值是代理类实例。this是当前对象的实例也就是InvocationHandler的实例。
5、method.invoke(o, args)方法,用来执行对象o的目标方法。在课程中的例子实际上就是那个UserDaoImpl对象的save方法。method.invoke方法的返回值是原方法的返回值。method.invoke方法的作用实际和直接“对象.方法名”调用作用是相同的
6、不能直接返回proxy对象。传入的参数proxy在我们重写的逻辑中没有直接用到,这只是父类中规定好的参数,我们重写时需要遵循。如果不return method.invoke就不会调用到想要调用的方法了。
因为我们增强时返回的是Proxy.newProxyInstance的实例,即外面的proxy代理对象。将来我们要使用它来进行调用,代理在调用的时候会自动调用invoke从而达到增强效果。如果不使用method.invoke就不会调用到真正的类的方法了。
如果同学还是不太理解,建议同学配合看一下后面的SpringAOP的 2-1 节JDK的动态代理课程
Spring的属性注入
对于类成员变量,注入方式有三种
-
构造函数注入
-
属性setter方法注入
-
接口注入(不常用)
Spring支持前两种
构造方法注入
通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用
构造器中注入在
<constructor-arg name="name" valve="张三">
set方法的属性注入
使用set方法注入,在Spring配置文件中,通过
第一种,value注入属性为普通类型的,如String,int型
<property name="" value="">
第二种,name为该类中的属性名,ref注入属性为对象的,值为其他bean的id或name
<property name="" ref="">
p名称空间的属性注入
-
使用p命名空间
-
为了简化XML文件配置,Spring从2.5开始引入一个新的p名称空间
-
普通属性:p:属性名="xxx" 引入常量值
-
属性为其他对象p:属性名-ref="xxx" 引用其它Bean对象
需要在xml配置文件中引入新头部xmlns:p="http://www.springframework.org/shema/p"
实例:
<bean id="person" class="com.imooc.ioc.demo4.Person" p:name="大黄" p:age="34" p:cat-ref="cat"/>
<bean id="cat" class="com.imooc.ioc.demo4.Cat" p:name="小黄"/>
Spring的属性注入-SqEL注入
(属性注入较为复杂时使用)
可以在#{.}里面调用其它类里面对应的方法
<property name="name" value="#{value}">
<property name="name" value="#{‘张三’}"/>
<property name="name" value="#{beanID.方法名()}">
SpEL表达式语言
语法:#{}
#{‘hello‘} : 使用字符串
#{beanId} : 使用另一个bean
#{beanId.content.toUpperCase()} : 使用指定名属性,并使用方法
#{T(java.lang.Math).PI} : 使用静态字段或方法
复杂类型的属性注入
<!--复杂类型的属性注入-->
<bean id="collectionBean" class="com.i.ioc.demo5.CollectionBean">
<!--数组类型-->
<property name="arrs">
<list>
<value>aaa</value>
<value>ccc</value>
<value>bbb</value>
</list>
</property>
<!--List集合类型属性注入-->
<property name="list">
<list>
<value>111</value>
<value>112</value>
<value>113</value>
</list>
</property>
<!--Set集合的属性注入-->
<property name="set">
<set>
<value>ddd</value>
<value>eee</value>
<value>fff</value>
</set>
</property>
<!--Map集合的属性注入-->
<property name="map">
<map>
<entry key="aaa" value="123"></entry>
<entry key="bbb" value="456"></entry>
<entry key="ccc" value="789"></entry>
</map>
</property>
<!--Properties的属性注入-->
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">1234</prop>
</props>
</property>
</bean>
以上是关于Spring入门到进阶 - Spring Bean管理 XML方式的主要内容,如果未能解决你的问题,请参考以下文章