Spring配置Bean有两种形式(XML和注解)
今天我们学习通过XML方式配置Bean
1、 Bean的配置方式
通过全类名(反射)的方式
√ id:标识容器中的bean。id唯一。
√ class:bean的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器
2、依赖注入的方式
1)属性注入:通过setter方法注入Bean的属性值或依赖的对象
属性注入使用<Property>元素,使用name指定Bean的属性名称,使用value指定Bean的属性的值
2)构造器注册:通过构造方法注入Bean的属性和值
首先创建一个Car类
1 public class Car { 2 private String brand; 3 private int speed; 4 private String color; 5 public Car(String brand, int speed, String color) { 6 this.brand = brand; 7 this.speed = speed; 8 this.color = color; 9 } 10 @Override 11 public String toString() { 12 return "Car [brand=" + brand + ", speed=" + speed + ", color=" + color + "]"; 13 } 14 15 }
然后加入配置文件配置节点
1 <bean id="car" class="com.hzg.spring.beans.Car"> 2 <constructor-arg value="Audi"></constructor-arg> 3 <constructor-arg value="120"></constructor-arg> 4 <constructor-arg value="black"></constructor-arg> 5 </bean>
Main方法开启Spring容器并使用
1 // 1.创建Spring 的IOC的容器对象 2 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 3 4 // 2.从IOC容器中获取bean实例 5 Car car = (Car)ctx.getBean(Car.class); 6 7// 3、调用hello方法 8 System.out.println(car);
输出结果:Car [brand=Audi, speed=120, color=black]
如果想指定给属性的顺序赋值,可以使用index属性
1 <bean id="car" class="com.hzg.spring.beans.Car"> 2 <constructor-arg value="Audi" index="0"></constructor-arg> 3 <constructor-arg value="120" index="1"></constructor-arg> 4 <constructor-arg value="black" index="2"></constructor-arg> 5 </bean>
如果想指定给属性的顺序赋值,也可以使用type属性
1 <bean id="car" class="com.hzg.spring.beans.Car"> 2 <constructor-arg value="Audi" type="java.lang.String"></constructor-arg> 3 <constructor-arg value="120" type="int"></constructor-arg> 4 <constructor-arg value="black" type="java.lang.String"></constructor-arg> 5 </bean>
3)工厂方法注入
此方式基本不用
3、引用其他Bean
1)引用外部Bean
1 <bean id="car" class="com.hzg.spring.beans.Car"> 2 <constructor-arg value="Audi" type="java.lang.String"></constructor-arg> 3 <constructor-arg value="120" type="int"></constructor-arg> 4 <constructor-arg value="black" type="java.lang.String"></constructor-arg> 5 </bean> 6 7 <bean id="person" class="com.hzg.spring.beans.Person"> 8 <property name="name" value="hzg"></property> 9 <property name="age" value="32"></property> 10 <!-- 使用 property的ref属性建立Bean之间的引用关系--> 11 <property name="car" ref="car"></property> 12 </bean>
使用 property的ref属性建立Bean之间的引用关系
2)引用内部Bean
1 <bean id="person" class="com.hzg.spring.beans.Person"> 2 <property name="name" value="hzg"></property> 3 <property name="age" value="32"></property> 4 <!-- 内部Bean,不能被外部引用,只能在内部使用--> 5 <property name="car"> 6 <bean class="com.hzg.spring.beans.Car"> 7 <constructor-arg value="Audi" type="java.lang.String"></constructor-arg> 8 <constructor-arg value="120" type="int"></constructor-arg> 9 <constructor-arg value="black" type="java.lang.String"></constructor-arg> 10 </bean> 11 </property> 12 </bean>
因为id是为了让外部引用,而内部Bean内部只用一次,不能被外部引用,随意不写id。
4、级联属性
1 <bean id="person" class="com.hzg.spring.beans.Person"> 2 <property name="name" value="hzg"></property> 3 <property name="age" value="32"></property> 4 <property name="car" ref="car"></property> 5 <!-- 级联属性赋值 --> 6 <property name="car.price" value="30000"></property> 7 </bean>
注意:属性想用car.price的级联,首先car必须要先初始化,否则会有异常
4、集合属性
当我们的Bean中有集合元素的时候,Spring中可以通过一组内置的xml标签(<list>、<set>、<map>)来配置集合属性。
1)List集合:
刚才的Person类有一个car属性,现在我们修改一下,Person类中有一个List<car>,即一个人拥有多辆车。
1 public class Person { 2 private String name; 3 private int age; 4 private List<Car> cars; 5 6 //为上面的3个属性设置getter和setter方法 7 public String getName() { 8 return name; 9 } 10 public void setName(String name) { 11 this.name = name; 12 } 13 public int getAge() { 14 return age; 15 } 16 public void setAge(int age) { 17 this.age = age; 18 } 19 public List<Car> getCars() { 20 return cars; 21 } 22 public void setCars(List<Car> cars) { 23 this.cars = cars; 24 } 25 }
配置文件修改如下:
1 <bean id="car1" class="com.hzg.spring.beans.Car"> 2 <constructor-arg value="Audi" type="java.lang.String"></constructor-arg> 3 <constructor-arg value="120" type="int"></constructor-arg> 4 <constructor-arg value="black" type="java.lang.String"></constructor-arg> 5 </bean> 6 <bean id="car2" class="com.hzg.spring.beans.Car"> 7 <constructor-arg value="Ford" type="java.lang.String"></constructor-arg> 8 <constructor-arg value="100" type="int"></constructor-arg> 9 <constructor-arg value="black" type="java.lang.String"></constructor-arg> 10 </bean> 11 <bean id="car3" class="com.hzg.spring.beans.Car"> 12 <constructor-arg value="Toyota" type="java.lang.String"></constructor-arg> 13 <constructor-arg value="95" type="int"></constructor-arg> 14 <constructor-arg value="black" type="java.lang.String"></constructor-arg> 15 </bean> 16 <bean id="person" class="com.hzg.spring.beans.Person"> 17 <property name="name" value="hzg"></property> 18 <property name="age" value="32"></property> 19 <!-- 集合属性(List),使用ref来配置子节点信息 --> 20 <property name="cars"> 21 <list> 22 <ref bean="car1"></ref> 23 <ref bean="car2"></ref> 24 <ref bean="car3"></ref> 25 </list> 26 </property> 27 </bean>
2)Map集合:
如果是<map>集合的话,只需要把list换成map即可。
1 <!-- 集合属性(Map),使用entry来配置map的子节点信息 --> 2 <property name="cars"> 3 <map> 4 <entry key="A" value-ref="car1" ></entry> 5 <entry key="B" value-ref="car2" ></entry> 6 </map> 7 </property>
3) 现在这么多集合Bean能不能抽出来,以供多个Bean进行引用,那么就需要使用util
1 <bean id="person" class="com.hzg.spring.beans.Person"> 2 <property name="name" value="hzg"></property> 3 <property name="age" value="32"></property> 4 <!-- 引用util --> 5 <property name="cars" ref="cars"></property> 6 </bean> 7 <util:list id="cars"> 8 <ref bean="car1"></ref> 9 <ref bean="car2"></ref> 10 </util:list>
4)使用p命名空间
Sping从2.5版本开始引入一个新的P的命名空间,通过使用P命名空间后,使得Xml的配置方式进一步简化
1 <!-- 通过P命名空间为Bean属性赋值,相对于传统的配置方式更加简洁 --> 2 <bean id="person" class="com.hzg.spring.beans.Person" p:name="hzg" p:age="32" p:cars-ref="cars"> 3 </bean>
5、使用autowire属性进行Bean的自动装配
当我们要往一个bean的某个属性里注入另外一个bean,我们会使用<property ref=“”>标签的形式。但是对于大型项目这种方式其实是不可取的。
1 <!-- 2 大型项目中我们一般使用autowire属性自动装备Bean,autowire属性有两个值:byName和byType 3 byName:根据Bean的名字和当前的Bean的setter属性名称进行装配 4 byType:根据Bean的类型进行装配,若有1个以上的类型,则抛异常 5 --> 6 <bean id="person" class="com.hzg.spring.beans.Person" autowire="byType"> 7 <property name="name" value="hzg"></property> 8 <property name="age" value="32"></property> 9 </bean>
自动装配的特点:
1)只有引用类型才可以自动装配。
2)autowire属性是在bean的级别上,一旦指定,当前bean的所有引用类型都必须使用自动装配。
3)byType和byName的只能选择其一。
6、配置上的继承(parent属性)
当我们有两个或者以上的同一个类型的Bean做实例化的时候,我们可以将一些公共的提成通用Bean。这样其他的Bean继承它即可以了。
1 <bean id="address1" class="com.hzg.Address" p:provice="Hebei" p:city="LangFang" p:street="YingBing"> 2 3 </bean> 4 <bean id="address2" class="com.hzg.Address" p:provice="Hebei" p:city="LangFang" p:street="YanLing"> 5 6 </bean> 7 <bean id="address3" class="com.hzg.Address" p:provice="Hebei" p:city="LangFang" p:street="YanShun"> 8 9 </bean>
以上Bean中用的都是address这个类,都是省市街道的赋值,只是在街道上每个不一样,所以我们完全可以把通用的提出来。
1 <bean id="address" class="com.hzg.Address" p:provice="Hebei" p:city="LangFang" p:street="YingBing"> 2 3 </bean> 4 <bean id="address1" parent="address" p:street="YanLing"> 5 6 </bean> 7 <bean id="address2" parent="address" p:street="YanShun"> 8 9 </bean>
7、Bean的作用域(scope属性)
<bean id="address" class="com.hzg.Address" p:provice="Hebei" p:city="LangFang" p:street="YanShun"> </bean>
1 ApplicationContext ctx = new ClassPathXmlApplicationContext("configspring.xml"); 2 Address address1 = (Address) ctx.getBean("address"); 3 Address address2 = (Address) ctx.getBean("address"); 4 System.out.println(address1==address2);
输出结果为:true
说明默认为单例模式的,它只要是看scope属性的。
使用Bean的scope属性来配置Bean的作用域的,scope有两个重要的属性值。
singleton:默认值,容器初始化时创建Bean实例,在整个容器的生命周期内只创建一个Bean,单例的。
prototype:原型的,容器初始化时不创建Bean的实例,而在每次请求时都创建一个新的Bean的实例,并返回。
8、使用外部属性文件(property-placeholder 属性占位符)
新建一个db.properties文件
1 user=root 2 password=123456 3 driverClass=com.mysql.jdbc 4 jdbcUrl=jdbc:mysql:///test
配置上属性占位符文件的地址,并在使用的过程中使用${}的格式取值
1 <!-- 导入属性文件 --> 2 <context:property-placeholder location="db.properties"></context:property-placeholder> 3 <bean id="dataSource" class="com.hzg.MyDataSource"> 4 <!-- 使用外部属性文件的属性值 --> 5 <property name="user" value="${user}"></property> 6 <property name="password" value="${password}"></property> 7 <property name="diverClass" value="${driverClass}"></property> 8 <property name="jdbcUrl" value="${jdbcUrl}"></property> 9 </bean>
MyDataSource文件:
1 public class MyDataSource { 2 private String user; 3 private String password; 4 private String diverClass; 5 private String jdbcUrl; 6 7 public String getUser() { 8 return user; 9 } 10 11 public void setUser(String user) { 12 this.user = user; 13 } 14 15 public String getPassword() { 16 return password; 17 } 18 19 public void setPassword(String password) { 20 this.password = password; 21 } 22 23 public String getDiverClass() { 24 return diverClass; 25 } 26 27 public void setDiverClass(String diverClass) { 28 this.diverClass = diverClass; 29 } 30 31 public String getJdbcUrl() { 32 return jdbcUrl; 33 } 34 35 public void setJdbcUrl(String jdbcUrl) { 36 this.jdbcUrl = jdbcUrl; 37 } 38 39 @Override 40 public String toString() { 41 return "MyDataSource{" + 42 "user='" + user + '\'' + 43 ", password='" + password + '\'' + 44 ", diverClass='" + diverClass + '\'' + 45 ", jdbcUrl='" + jdbcUrl + '\'' + 46 '}'; 47 } 48 }
Main方法:
1 ApplicationContext ctx = new ClassPathXmlApplicationContext("configspring.xml"); 2 MyDataSource myDataSource = (MyDataSource) ctx.getBean("dataSource"); 3 System.out.println(myDataSource);
输出结果:MyDataSource{user='root', password='123456', diverClass='com.mysql.jdbc', jdbcUrl='jdbc:mysql:///test'}
9、Spring表达式SPEL表达式
1 <bean id="person" class="com.hzg.Person"> 2 <!-- 使用SpEL 来应用其他的Bean --> 3 <property name="car" value="#{car}"></property> 4 <!-- 使用SpEL 来应用其他的Bean的属性 --> 5 <property name="city" value="#{address.city}"></property> 6 <!-- 使用SpEL 中使用运算符 --> 7 <property name="info" value="#{car.price > 30000 ? '金领' : '白领'}"></property> 8 <!-- 使用SpEL 引用类的静态属性 --> 9 <property name="yaowei" value="#{T(java.lang.Math).PI * 80}"></property> 10 </bean>
10、Spring中Bean的生命周期
1)创建Bean的实例
2)为Bean的属性设置值和对其他Bean的引用
3)Bean后置处理器postProcessBeforeInitialization方法
4)调用Bean的初始化方法(init-method)
5)Bean后置处理器的postProcessAfterInitialization方法
6)Bean正常使用
7)当容器关闭时,调用Bean的销毁方法(destroy-method)
实例:
1 public class Car { 2 public Car() { 3 System.out.println("构造器……"); 4 } 5 private String brand; 6 7 public void setBrand(String brand) { 8 System.out.println("设置属性……"); 9 this.brand = brand; 10 } 11 public void init(){ 12 System.out.println("初始化……"); 13 } 14 public void destroy(){ 15 System.out.println("销毁……"); 16 } 17 }
MyBeanProcessor必须实现BeanPostProcessor接口的两个方法
1 public class MyBeanProcessor implements BeanPostProcessor { 2 @Override 3 public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { 4 System.out.println("postProcessBeforeInitialization……"); 5 return o; 6 } 7 8 @Override 9 public Object postProcessAfterInitialization(Object o, String s) throws BeansException { 10 System.out.println("postProcessAfterInitialization……"); 11 return o; 12 } 13 }
配置文件
1 <bean id="car" class="com.hzg.Car" p:brand="Audi" init-method="init" destroy-method="destroy"></bean> 2 <!-- 配置Bean的后置处理器 --> 3 <bean class="com.hzg.MyBeanProcessor"></bean>
Main方法
1 public static void main(String[] args) { 2 //由于ApplicationContext没有close方法,所以要使用它下面接口ConfigurableApplicationContext 3 ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("configspring.xml"); 4 Car car = (Car) ctx.getBean("car"); 5 System.out.println("使用Bean:" + car.toString()); 6 //关闭IOC容器 7 ctx.close(); 8 }
输出结果:
postProcessBeforeInitialization……
postProcessAfterInitialization……
构造器……
设置属性……
postProcessBeforeInitialization……
初始化……
postProcessAfterInitialization……
使用Bean:com.hzg.Car@2d928643
销毁……
-------------------------------------------------------------------------------------------------------------------------
跟着刚哥学习Spring框架系列:
跟着刚哥学习Spring框架--创建HelloWorld项目(一)
跟着刚哥学习Spring框架--Spring容器(二)
跟着刚哥学习Spring框架--通过XML方式配置Bean(三)
跟着刚哥学习Spring框架--通过注解方式配置Bean(四)
跟着刚哥学习Spring框架--AOP(五)
跟着刚哥学习Spring框架--JDBC(六)
跟着刚哥学习Spring框架--事务配置(七)