一.概念
1.轻量级开源框架;
2.简化企业级应用而生;
3.是一个IOC(DI)依赖注入
和AOP(面向切面编程
)容器框架;
4.在IOC和AOP基础上可以整合各种企业应用的开源框架和优秀的第三方类库
二.配置eclipse
以下是不同的eclipse对应的sts版本,请查看好自己的eclipse下载对应的版本
eclipse-kepler.4.3.1–>springsource-tool-suite-RELEASE-e4.3.1-updatesite.zip
eclipse-Mars.4.5.1–>springsource-tool-suite-3.7.2RELEASE-e4.5.1-updatesite.zip
eclipse-Mars.4.5.2–>springsource-tool-suite-3.7.3RELEASE-e4.5.2-updatesite.zip
eclipse-neno.4.6–>springsource-tool-suite-3.7.3RELEASE-e4.6-updatesite.zip
我的版本是eclipse-Mars.4.5.2安装完毕后,welcome页面显示Spring tool,但是在window->properties中却没有spring选项,而且安装完毕后在properties中连maven选项也不见了,这个问题整整折腾了我半天时间,卸了装,装了卸还是不行,最后问同事用的是eclipse-neno.4.6.3发行版,下载eclipse-neno.4.6.3
下载后打开,提示JDK环境必须是JDK1.8以上,于是从JDK1.7升级到JDK1.8,
安装步骤如下:我用的是(springsource-tool-suite-3.8.4.RELEASE-e4.6.3-updatesite.zip
)下载地址:https://spring.io/tools/sts/all
安装完毕后在window->Preperences中就可以看到spring选项了;
到此为止eclipse中spring插件配置结束,这个汗....
三.第一个helloWorld
下载spring最新稳定版本,下载方式请查看:
http://www.cnblogs.com/yy3b2007com/p/6783699.html新建java下过目,spring-1
-
加载jar包(以下橙色背景的四个核心jar包必须加载)
自己下载commons-logging.jar包并加载进去
-
目录结构:
HelloWorld内容:
package com.lxf.spring.bean;
public class HelloWorld {
private String name;
public void setName(String name)
{
System.out.println("setName:"+name);
this.name = name;
}
public void hello()
{
System.out.println("hello: "+this.name);
}
public HelloWorld()
{
System.out.println("init HelloWorld...");
}
}
- Spring Bean Configuration File内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.2.xsd">
<!-- 配置bean -->
<bean id="helloWorld" class="com.lxf.spring.bean.HelloWorld">
<property name="name" value="zhangsan"></property>
</bean>
</beans>
- Main.java内容
package com.lxf.spring.bean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args)
{
/*
HelloWorld helloworld = new HelloWorld();
helloworld.setName("liangxifeng");
*/
//1.创建spring的IOC容器对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.从IOC容器中获取Bean实例
//HelloWorld helloworld = (HelloWorld)ctx.getBean("helloWorld");
//helloworld.setName("aaa");
//3.调用hello方法
// helloworld.hello();
}
}
四.IOC(inversion of Control)和 DI(Dependency Injection)
- IOC概念:
- 思想是
反转资源获取的方向
- 传统的资源查找方式要求组件向容器发起请求查找资源.作为回应,容器实时的返回资源;
- 应用了IOC之后,则是容器主动地就将资源推送给它所管理的组件
- 组件所要做的只是选择一种合适的方式来接收资源;(也称查找的被动形式)
- DI概念
- IOC的另一种表达方式:即组件以一些预定义好的方式(例如:setter方法)接收来自容器的资源注入,相对IOC而言,这种表述更直接;
五.IOC的前生
ReprotService要想生成报表需要依赖三个类,
耦合度很高
.
使用工厂模式ReprotService要想生成报表需要依赖两个类,
耦合度降低
.
使用反转控制ReprotService要想生成报表需要依赖一个类,
耦合度最低
.
六.spring容器
在Spring IOC容器读取Bean配置之前,自身要先实例化;
Spring提供了两种类型的IOC容器实现;
(1). BeanFactory:IOC容器的基本实现(BeanFactory是spring框架的基础设施,面向Spring本身)
(2). ApplicationContext 是BeanFactory的子接口,提供了更丰富的功能;(ApplicationContext 面向Spring框架的开发者,几乎所有应用场合都直接使用ApplicationContext而非底层的BeanFactory)-
ApplicationContext有两个实现类
属性的注入方式一(setter方法)
<!--
配置bean
class:bean全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参构造器
id:标识容器中的bean 必须唯一
-->
<bean id="helloWorld" class="com.lxf.spring.bean.HelloWorld">
<property name="name" value="zhangsan"></property>
</bean>
private String name;
public void setName(String name)
{
System.out.println("setName:"+name);
this.name = name;
}
- 属性的注入方式二(构造方法注入)
- 通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用
- 构造器注入在<constructor-arg>元素里声明属性,<constructor-arg>中没有name属性;
- 使用构造器注入属性值可以指定参数的位置和参数类型,以区分重载构造器
<!-- 通过构造器的方式实现属性注入,可以指定参数的位置和参数类型,以区分重载构造器-->
<bean id="car1" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽车1" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
<!-- 通过构造器的方式实现属性注入,可以指定参数的位置和参数类型,以区分重载构造器 -->
<bean id="car2" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽车2" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="120" index="1" type="int"></constructor-arg>
</bean>
以上两个bean,根据参数类型区分实例化的时候调用哪个构造器
Bean类Car
package com.lxf.spring.bean;
public class Car {
private String cName;
private double price;
private int speed;
/**
* 构造器,为汽车名字和汽车价格属性初始化值
* @param cName
* @param price
*/
public Car(String cName, double price) {
super();
this.cName = cName;
this.price = price;
}
/**
* 重载构造器,为汽车名字和汽车速度初始化值
* @param cName
* @param speed
*/
public Car(String cName, int speed) {
super();
this.cName = cName;
this.speed = speed;
}
@Override
public String toString() {
return "Car [cName=" + cName + ", price=" + price + ", speed=" + speed + "]";
}
}
测试:
Car car = (Car) ctx.getBean("car1");
System.out.println(car);
Car car = (Car) ctx.getBean("car2");
System.out.println(car);
输出:
Car [cName=汽车1, price=150000.0, speed=0]
Car [cName=汽车2, price=0.0, speed=120]
- 属性值也可以使用value子结点进行那个配置(字面值)
<!-- 使用value子结点进行配置value值,如果value值包含特殊字符,则使用<![CDATA[]]包裹起来 -->
<bean id="car1-1" class="com.lxf.spring.bean.Car">
<constructor-arg index="0" type="java.lang.String">
<value><![CDATA[<汽车1-1*>]]></value>
</constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
Car car3 = (Car) ctx.getBean("car1-1");
System.out.println(car3);
输出:
Car [cName=<汽车1-1*>, price=150000.0, speed=0]
- bean之间的相关互引用
person类
package com.lxf.spring.bean;
public class Person {
//姓名
private String name;
//年龄
private int age;
//该人所拥有的汽车
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
}
配置bean文件:
<bean id="car1" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽车1" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
<bean id="persion" class="com.lxf.spring.bean.Person">
<property name="name" value="lisi"></property>
<property name="age" value="28"></property>
<!-- 使用property的ref属性建立bean之间的引用关系 -->
<!-- <property name="car" ref="car1"></property>-->
<!-- 和上面等效 -->
<!--
<property name="car">
<ref bean="car1"/>
</property>-->
<!-- 使用内部bean,等效与以上,内部bean不能被外部访问 -->
<property name="car">
<bean class="com.lxf.spring.bean.Car">
<constructor-arg value="汽车1" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
</property>
七.级联属性赋值
<bean id="car" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽车2" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="120" index="1" type="int"></constructor-arg>
</bean>
<bean id="persion2" class="com.lxf.spring.bean.Person">
<constructor-arg value="wangwu"></constructor-arg>
<constructor-arg value="30"></constructor-arg>
<!-- 测试赋值null
<constructor-arg><null/></constructor-arg>-->
<constructor-arg ref="car"></constructor-arg>
<!-- 级联属性赋值 -->
<property name="car.price" value="12"></property>
</bean>
八.集合属性赋值
(1)List类型配置
Person类中有属性
//该人所拥有的汽车集合
private List<Car> cars;
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
spring配置bean
<!-- 通过构造器的方式实现属性注入,可以指定参数的位置和参数类型,以区分重载构造器-->
<bean id="car1" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽车1" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="150000" index="1" type="double"></constructor-arg>
</bean>
<!-- 通过构造器的方式实现属性注入,可以指定参数的位置和参数类型,以区分重载构造器 -->
<bean id="car2" class="com.lxf.spring.bean.Car">
<constructor-arg value="汽车2" index="0" type="java.lang.String"></constructor-arg>
<constructor-arg value="120" index="1" type="int"></constructor-arg>
</bean>
<!--集合属性赋值 -->
<bean id="person3" class="com.lxf.spring.bean.Person">
<constructor-arg value="wangwu--1"></constructor-arg>
<constructor-arg value="30"></constructor-arg>
<constructor-arg><null/></constructor-arg>
<property name="cars">
<list>
<ref bean="car1"/>
<ref bean="car2"/>
</list>
</property>
</bean>
(2)Map类型属性赋值
Person类中的属性
//map类型的汽车
private Map<String,Car> mapCars;
public Map<String, Car> getMapCars() {
return mapCars;
}
public void setMapCars(Map<String, Car> mapCars) {
this.mapCars = mapCars;
}
Spring配置
<!-- 集合map属性赋值 -->
<bean id="person4" class="com.lxf.spring.bean.Person" >
<constructor-arg value="赵六"></constructor-arg>
<constructor-arg value="33"></constructor-arg>
<constructor-arg><null/></constructor-arg>
<property name="mapCars">
<!-- 使用map节点以及map节点子节entry配置 map类型的属性 -->
<map>
<entry key="AA" value-ref="car1"></entry>
<entry key="BB" value-ref="car2"></entry>
</map>
</property>
</bean>
(3)Properites属性赋值
DataSource实体类
package com.lxf.spring.bean;
import java.util.Properties;
public class DataSource {
private Properties properties;
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "DataSource [properties=" + properties + "]";
}
}
(4)使用Utility scheme定义集合
使用Utility schema里的集合标签定义独立的集合Bean,必须在Bean根元素里面定义;
这样定义的集合就可以被其他Bean共享
注意:需要导入util命名空间
Person实体类属性
//该人所拥有的汽车集合
private List<Car> cars;
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars = cars;
}
Spring配置
<!-- 配置单独的集合bean,以供多个bean进行引用,注意:需要导入util命名空间 -->
<util:list id="cars">
<ref bean="car1"/>
<ref bean="car2"/>
</util:list>
<bean id="person5" class="com.lxf.spring.bean.Person">
<constructor-arg value="小青"></constructor-arg>
<constructor-arg value="33"></constructor-arg>
<constructor-arg><null/></constructor-arg>
<property name="cars" ref="cars"></property>
</bean>
从Spring2.5起可以使用P命名空间为bean属性赋值
Spring配置(注意:需导入 p 命名空间,导入方式类似util命名空间)
<!-- 通过 p 命名空间为bean属性赋值,需要先导入 p 命名空间,相对于传统方式更加简洁 -->
<bean id="person6" class="com.lxf.spring.bean.Person" p:age="29" p:name="小网" p:cars-ref="cars"></bean>
九.bean的自动装配
使用autowire属性指定自动装配的方式,
(1) byName根据其他bean的id值和当前bean的setter风格属性名进行自动装配,如果没有匹配的bean则不装配
(2)byType根据其他bean的类型和当前bean属性的类型进行自动装配,若IOC容器中有一个以上的类型匹配的bean,则抛异常
<bean id="address" class="com.lxf.spring.autowire.Address" p:city="Beijing" p:street="huilongguan">
</bean>
<bean id="car" class="com.lxf.spring.autowire.Car" p:brand="Audi" p:price="300000"></bean>
<!-- 使用autowire属性指定自动装配的方式,
byName根据其他bean的id值和当前bean的setter风格属性名进行自动装配,如果没有匹配的bean则不装配
byType根据其他bean的类型和当前bean属性的类型进行自动装配,若IOC容器中有一个以上的类型匹配的bean,则抛异常 -->
<bean id="person" class="com.lxf.spring.autowire.Person" p:name="zs" autowire="byType"></bean>
自动装配缺点:
(1)如果使用autowire属性自动装配,那么只要使用autowire的bean中引用其他bean属性的值都自动装载,不能指定某一个或几个属性使用自动装载;
(2)自动装载byType方式,如果一个Spring配置文件中有多个引用类型,则该方式会不知道装载哪个,会抛出异常;
所以在平时开发中尽量使用手动配置,整合其他框架的时候才使用自动装载
十.Bean之间的关系继承
- Spring允许继承Bean的配置,称为父Bean和子Bean;
- 子Bean从父Bean中继承配置,包括Bean的属性配置;
- 子Bean也可以覆盖父Bean继承来的配置;
- 父Bean可以作为配置模板,也可以作为Bean实例,可以设置<bean>的abstract属性为true,这样Spring将不会实例化这个Bean;
- 并不是Bean元素里面的所有属性都会被继承,比如:autowire abstract等不会被继承
- 也可以忽略父Bean的class属性,让子Bean指定自己的类,而共享相同属性配置,但此时
abstract必须设为true
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 属性abstract=true代表设置该bean为模板(不能被容器实例化),如果为模板则不需要配置 -->
<bean id="address1" class="com.lxf.spring.autowire.Address" p:city="Beijing" p:street="wudaokou" abstract="true"></bean>
<!-- 使用parent属性继承其他bean配置 -->
<bean id="address2" p:street="dazhongsi" parent="address1"></bean>
</beans>
十一.Bean之间的关系依赖
- 使用depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好;
- 如果前置依赖多个Bean,则可以通过逗号,空格或的方式配置Bean的名称;
<bean id="car" class="com.lxf.spring.autowire.Car"></bean>
<!-- 使用depends-on属性设定Bean前置依赖的Bean,必须提前配置car的bean -->
<bean id="person" class="com.lxf.spring.autowire.Person" p:name="zs" depends-on="car" p:car-ref="car"></bean>
十二.Bean的作用域
-
默认单例: bean属性scope=singleton(默认值),IOC容器初始化的时创建bean实例,在整个容器的生命周期内只创建一个bean,单例的; 比如:
Car类有无参构造器:
public class Car {
private String brand;
private double price;
public Car()
{
System.out.println("Car is Constract...");
}
}
Spring配置
<!--
使用bean的scope属性配置bean的作用域,scope值如下:
singleton:默认值,IOC容器初始化的时创建bean实例,在整个容器的生命周期内只创建一个bean,单例的;
-->
<bean id="car" class="com.lxf.spring.autowire.Car" p:brand="Audi" p:price="300000" scope="singleton"></bean>
main方法测试:
//创建spring的IOC容器对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-scope.xml");
输出:
Car is Constract...
证明容器在初始化的时候创建单例bean;
main方法测试:
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-scope.xml");
Car car1 = (Car)ctx.getBean("car");
Car car2 = (Car)ctx.getBean("car");
System.out.println(car1==car2);//输出true
以上car1=car2,证明每次调用bean的使用都是
-
多例: bean属性scope=prototype(原型的),IOC容器初始化时不创建bean实例,而在每次请求时都创建一个新的Bean实例,并返回,比如:
修改上面的Spring配置
<!--
使用bean的scope属性配置bean的作用域,scope值如下:
singleton:默认值,IOC容器初始化的时创建bean实例,在整个容器的生命周期内只创建一个bean,单例的;
prototype:原型的,IOC容器初始化时不创建bean实例,而在每次请求时都创建一个新的Bean实例,并返回;
-->
<bean id="car" class="com.lxf.spring.autowire.Car" p:brand="Audi" p:price="300000" scope="prototype"></bean>
main方法测试:
//创建spring的IOC容器对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-scope.xml"); //不创建bean实例
Car car1 = (Car)ctx.getBean("car"); //创建一个bean实例
Car car2 = (Car)ctx.getBean("car");//再次创建一个bean实例
System.out.println(car1==car2);//返回false
十三.配置bean中使用外部属性文件
- 首先在Spring配置文件中打开context命名空间;
- src下新建db.properties属性配置文件
userName=root
pass=123456
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///test
- 在Spring配置文件(beans-properties.xml)中引用该配置文件中的属性变量
<!-- 导入属性文件 classpath代表类路径 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 使用外部属性文件的属性 -->
<property name="user" value="${userName}"></property>
<property name="password" value="${pass}"></property>
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
</bean>
- main方法测试:
//1.创建spring的IOC容器对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-properties.xml");
//获取数据源
DataSource dataSource = (DataSource)ctx.getBean("dataSource");
//打印数据库连接
System.out.println(dataSource.getConnection());
输出结果:
com.mchange.v2.c3p0.impl.NewProxyConnection@ee3d0a5
- 以上测试需要加入:
c3p0-0.9.1.2.jar
和jdbc jar包
,其中C3P0是一个开源的JDBC连接池
十四.Spring的spel表达式
<bean id="address" class="com.lxf.spring.spel.Address">
<property name="city" value="#{'北京'}"></property>
<property name="street" value="五道口"></property>
</bean>
<bean id="car" class="com.lxf.spring.spel.Car">
<property name="brand" value="Audi"></property>
<property name="price" value="500000"></property>
<!-- 使用SPEL引用类的静态属性,并在SPEL表达式中进行计算 -->
<property name="tyrePerimeter" value="#{T(java.lang.Math).PI*80}"></property>
</bean>
<bean id="person" class="com.lxf.spring.spel.Person">
<property name="name" value="张三"></property>
<!-- 使用spel来引用其他bean -->
<property name="car" value="#{car}"></property>
<!-- 使用spel来引用其他bean属性 -->
<property name="city" value="#{address.city}"></property>
<!-- 在spel中使用运算符 -->
<property name="work" value="#{car.price>300000 ? '金领' : '白领'}"></property>
</bean>
十五.IOC容器中Bean的生命周期
举例如下:
(1)Car实体类:
package com.lxf.spring.cycle;
/**
* 汽车实体类
* @author lxf
*/
public class Car {
private String brand;
private double price;
//轮胎周长
private double tyrePerimeter;
/**
* 无参数构造器
*/
public Car()
{
System.out.println("Car is Constract...");
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
System.out.println("setBrand为品牌属性赋值");
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getTyrePerimeter() {
return tyrePerimeter;
}
public void setTyrePerimeter(double tyrePerimeter) {
this.tyrePerimeter = tyrePerimeter;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + ", tyrePerimeter=" + tyrePerimeter + "]";
}
/**
* Bean初始化方法,在IOC容器启动的时候调用
*/
public void myInit()
{
System.out.println("创建了IOC容器:调用Bean的初始化方法");
}
/**
* Bean销毁方法,在IOC容器关闭的时候调用
*/
public void myDestroy()
{
System.out.println("调用Bean的销毁方法,IOC容器关闭了");
}
}
(2)Spring配置文件(beans-cycle.xml)
<!--
bean的init-method属性调用对应类中的自定义方法myInit方法,在IOC容器创建的时候执行
bean的destroy-method属性调用对应类中的自定义方法myDestroy,在IOC容器关闭的时候执行
-->
<bean id="car" class="com.lxf.spring.cycle.Car"
init-method="myInit"
destroy-method="myDestroy">
<property name="brand" value="Audi"></property>
</bean>
(3)main方法测试
//创建spring的IOC容器对象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
Car car1 = (Car)ctx.getBean("car");
System.out.println("使用Bean: "+car1);
//关闭IOC容器
ctx.close();
输出结果如下:
Car is Constract...
setBrand为品牌属性赋值
创建了IOC容器:调用Bean的初始化方法
使用Bean: Car [brand=Audi, price=0.0, tyrePerimeter=0.0]
...
调用Bean的销毁方法,IOC容器关闭了
修改以上代码加入后置处理器bean的生命周期:
(1)新建后置处理器MyBeanPostProcessor
package com.lxf.spring.cycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* bean的init-method方法之后调用
* 参数:
* bean: IOC传递进来的bean实例
* beanName:bean的id
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
if("car".equals(beanName))
{
System.out.println("bean的init-method方法之后调用:"+bean);
}
return bean;
}
/*
* bean的init-method方法之前调用
* 参数:
* bean: IOC传递进来的bean实例
* beanName:bean的id
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
if("car".equals(beanName))
{
System.out.println("bean的init-method方法之前调用:"+bean);
Car car = new Car();
car.setBrand("大众");
//对bean重新赋值
bean = car;
}
return bean;
}
}
(2)Spring配置文件beans-cycle.xml修改
<!--
bean的init-method属性调用对应类中的自定义方法myInit方法,在IOC容器创建的时候执行
bean的destroy-method属性调用对应类中的自定义方法myDestroy,在IOC容器关闭的时候执行
-->
<bean id="car" class="com.lxf.spring.cycle.Car"
init-method="myInit"
destroy-method="myDestroy">
<property name="brand" value="Audi"></property>
</bean>
<!-- 配置bean的后置处理器: 不需要配置id, IOC容器自动识别 -->
<!--
实现BeanPostProcessor接口,并具体实现
postProcessBeforeInitialization(Object bean, String beanName):init-method之前被调用
postProcessAfterInitialization(Object bean, String beanName) :init-method之后被调用
以上两个方法参数:
bean: bean实例本身
beanName: IOC容器配置的bean的id
以上两个方法返回值:
实际上返回给用户的那个Bean,注意:可以在以上两个方法中修改返回的Bean,甚至返回一个新Bean
-->
<bean class="com.lxf.spring.cycle.MyBeanPostProcessor"></bean>
(3)main方法测试:
//创建spring的IOC容器对象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
Car car1 = (Car)ctx.getBean("car");
System.out.println("使用Bean: "+car1);
//关闭IOC容器
ctx.close();
输出结果:
Car is Constract...
setBrand为品牌属性赋值
bean的init-method方法之前调用:Car [brand=Audi, price=0.0, tyrePerimeter=0.0]
Car is Constract...
setBrand为品牌属性赋值
创建了IOC容器:调用Bean的初始化方法
bean的init-method方法之后调用:Car [brand=大众, price=0.0, tyrePerimeter=0.0]
使用Bean: Car [brand=大众, price=0.0, tyrePerimeter=0.0]
调用Bean的销毁方法,IOC容器关闭了
十六.使用工厂方法创建Bean
举例:
(1)新建静态工厂方法类:StaticFactory
package com.lxf.spring.factory;
import java.util.HashMap;
import java.util.Map;
/**
* 静态工厂方法:直接调用某一个类的静态方法可以返回Bean实例
* @author lxf
*
*/
public class StaticFactory {
private static Map<String,Car> cars = new HashMap<String,Car>();
static{
cars.put("audi", new Car("audi"));
cars.put("ford", new Car("ford"));
}
/**
* 静态工厂方法返回对应Bean实例
* @param name
* @return
*/
public static Car getCar(String name)
{
return cars.get(name);
}
}
(2)Spring配置文件beans-factory.xml
<!-- 通过静态方法工厂配置bean, 注意不是配置静态方法实例,而是bean实例 -->
<!--
class属性:指向静态工厂方法的全类名
factory-method属性:指向静态工厂方法名
constructor-arg标签:如果工厂方法需要传入参数,则使用constructor-arg标签来配置
-->
<bean id="car1"
class="com.lxf.spring.factory.StaticFactory"
factory-method="getCar">
<constructor-arg value="audi" /></bean>
(3)man方法测试:
//创建spring的IOC容器对象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factory.xml");
Car car1 = (Car)ctx.getBean("car1");
System.out.println("使用Bean: "+car1);
输出:
使用Bean: Car [brand=audi, price=0.0, tyrePerimeter=0.0]
举例:
(1)新建实例工厂方法类:InstanceFactory
package com.lxf.spring.factory;
import java.util.HashMap;
import java.util.Map;
/**
* 实例工厂方法:实例工厂的方法,即先需要创建工厂本身实例,
* 再调用工厂的实例方法来返回bean的实例.
* @author lxf
*/
public class InstanceFactory {
private Map<String,Car> cars = null;
public InstanceFactory()
{
cars = new HashMap<String,Car>();
cars.put("audi", new Car("audi"));
cars.put("ford", new Car("ford"));
}
public Car getCar(String name)
{
return cars.get(name);
}
}
(2)Spring配置文件(beans-factory.xml)
<!-- 先创建工厂实例本身 -->
<bean id="factory" class="com.lxf.spring.factory.InstanceFactory"></bean>
<!-- 在通过实例工厂方法配置bean实例 -->
<!--
factory-bean属性:指向实例工厂方法的bean
factory-method属性:指向实例厂方法名
constructor-arg标签:如果工厂方法需要传入参数,则使用constructor-arg标签来配置
-->
<bean id="car2" factory-bean="factory" factory-method="getCar">
<constructor-arg value="ford"></constructor-arg>
</bean>
(3)mani方法测试:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factory.xml");
Car car2 = (Car)ctx.getBean("car2");
System.out.println("使用Bean: "+car2);
输出:
使用Bean: Car [brand=ford, price=0.0, tyrePerimeter=0.0]
使用FactoryBean的方式配置Bean
- 其实就是自己定义一个类,实现Spring的FactoryBean接口,实现该接口的三个方法即可;(其中有一个方法返回Bean实例)
package com.lxf.spring.factorybean;
import org.springframework.beans.factory.FactoryBean;
/**
* 通过FactoryBean的方式配置Bean,需要实现FactoryBean接口
* @author lxf
* @param <T>
*/
public class CarFactoryBean<T> implements FactoryBean<T> {
private String brand;
public void setBrand(String brand) {
this.brand = brand;
}
@Override
/**
* 返回bean对象
*/
public T getObject() throws Exception {
// TODO Auto-generated method stub
return (T) new Car(brand,5000000);
}
@Override
/**
* 返回Bean类型
*/
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Car.class;
}
@Override
/**
* 是否是单例
*/
public boolean isSingleton() {
// TODO Auto-generated method stub
return true;
}
}
- 在Spring配置文件中beans-facotrybean.xml中配置自己定义的类
<!--
通过FactoryBean类配置Bean的实例
class:指向FactoryBean的全类名
property:配置FactoryBean的属性
但实际返回的实例确实FacboryBean的getObject()方法返回的实例
-->
<bean id="car" class="com.lxf.spring.factorybean.CarFactoryBean">
<property name="brand" value="BMW"></property>
</bean>
- main方法测试:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factorybean.xml");
Car car1 = (Car)ctx.getBean("car");
System.out.println("使用Bean: "+car1);
输出:
使用Bean: Car [brand=BMW, price=5000000.0, tyrePerimeter=0.0]
使用注解的方式配置bean
注意:需要引入spring-aop-4.3.9.RELEASE.jar
Spring配置文件beans-annotation.xml配置
<!--
指定Spring IOC容器的扫描包,IOC容器在启动的时候,
会扫表base-package指定的当前包以及子包下所有包含指定注解的bean,并将其实例
可通过resource-pattern="repository/*.class"指定扫描资源
<context:component-scan
base-package="com.spring.beans.annotation"
resource-pattern="repository/*.class">
</context:component-scan> -->
<!-- 排除指定注解下的目标类
<context:component-scan
base-package="com.spring.beans.annotation" >
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>-->
<!-- 包含指定注解下的目标类 context:include-filter要和use-default-filters属性配合使用(默认扫描所有相关注解)
<context:component-scan
base-package="com.spring.beans.annotation" use-default-filters="false" >
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>-->
<!-- 排除指定类bean的加载
<context:component-scan
base-package="com.spring.beans.annotation" >
<context:exclude-filter type="assignable" expression="com.spring.beans.annotation.repository.UserRepositoryImpl"/>
</context:component-scan>-->
<!-- 包含指定类bean的加载 context:include-filter需要和use-default-filter属性配合使用-->
<context:component-scan
base-package="com.spring.beans.annotation" use-default-filters="false">
<context:include-filter type="assignable" expression="com.spring.beans.annotation.repository.UserRepositoryImpl"/>
</context:component-scan>
以上目录结构:
src
|__com.spring.beans.annotation
| |__Main.java
| |__TestObject.java
| |__service
| |__UserService.java
| |__respository
| |__UserRespository.java
| |__controller
| |__UserController.java
|__beans.annotation.xml
UserService.java类带有@Service注解
package com.spring.beans.annotation.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void add()
{
System.out.println("UserService add...");
}
}
其他User*.java分别带有如下注解
@Repository("userRepository")
@Controller
@Repository("userRepository"
Bean之间属性互相依赖的解决方案:
package com.spring.beans.annotation.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import com.spring.beans.annotation.TestObject;
import com.spring.beans.annotation.repository.UserRepository;
import com.spring.beans.annotation.service.UserService;
@Controller
public class UserController {
@Autowired
private UserService userService;
@Autowired
//如果IOC容器中存在多个UserRepository接口的实现类,
//可以指定具体装在哪个实现类,注意首字母小写(spring规定)
@Qualifier("jdbcRespository")
private UserRepository userRepository;
//如果IOC容器中没有testObj这个bean,则使用@Autowired(required=false,否则异常
@Autowired(required=false)
private TestObject testObj;
public void execute()
{
System.out.println("UserControler execute...");
userService.add();
}
}
十七.Spring4.* 泛型的依赖注入
在实际开发中,往往我们可以将一些结构职能相似的类抽象出一定的泛型超类。这样相应结构中的类之间的依赖关系我们可以通过泛型超类来建立,而其他的子类只要继承了它们,就能够建立相应的依赖关系:
参考链接:https://my.oschina.net/happyBKs/blog/482508