一.概念
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内容:
- 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方法)
private String name;
public void setName(String name)
{
System.out.println("setName:"+name);
this.name = name;
}
- 属性的注入方式二(构造方法注入)
- 通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用
- 构造器注入在
元素里声明属性, 中没有name属性; - 使用构造器注入属性值可以指定参数的位置和参数类型,以区分重载构造器
以上两个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子结点进行那个配置(字面值)
]]>
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文件:
七.级联属性赋值
八.集合属性赋值
(1)List类型配置
Person类中有属性
//该人所拥有的汽车集合
private List cars;
public List getCars() {
return cars;
}
public void setCars(List cars) {
this.cars = cars;
}
spring配置bean
(2)Map类型属性赋值
Person类中的属性
//map类型的汽车
private Map mapCars;
public Map getMapCars() {
return mapCars;
}
public void setMapCars(Map mapCars) {
this.mapCars = mapCars;
}
Spring配置
(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 cars;
public List getCars() {
return cars;
}
public void setCars(List cars) {
this.cars = cars;
}
Spring配置
从Spring2.5起可以使用P命名空间为bean属性赋值
Spring配置(注意:需导入 p 命名空间,导入方式类似util命名空间)
九.bean的自动装配
使用autowire属性指定自动装配的方式,
(1) byName根据其他bean的id值和当前bean的setter风格属性名进行自动装配,如果没有匹配的bean则不装配
(2)byType根据其他bean的类型和当前bean属性的类型进行自动装配,若IOC容器中有一个以上的类型匹配的bean,则抛异常
自动装配缺点:
(1)如果使用autowire属性自动装配,那么只要使用autowire的bean中引用其他bean属性的值都自动装载,不能指定某一个或几个属性使用自动装载;
(2)自动装载byType方式,如果一个Spring配置文件中有多个引用类型,则该方式会不知道装载哪个,会抛出异常;
所以在平时开发中尽量使用手动配置,整合其他框架的时候才使用自动装载
十.Bean之间的关系继承
- Spring允许继承Bean的配置,称为父Bean和子Bean;
- 子Bean从父Bean中继承配置,包括Bean的属性配置;
- 子Bean也可以覆盖父Bean继承来的配置;
- 父Bean可以作为配置模板,也可以作为Bean实例,可以设置
的abstract属性为true,这样Spring将不会实例化这个Bean; - 并不是Bean元素里面的所有属性都会被继承,比如:autowire abstract等不会被继承
- 也可以忽略父Bean的class属性,让子Bean指定自己的类,而共享相同属性配置,但此时
abstract必须设为true
十一.Bean之间的关系依赖
- 使用depends-on属性设定Bean前置依赖的Bean,前置依赖的Bean会在本Bean实例化之前创建好;
- 如果前置依赖多个Bean,则可以通过逗号,空格或的方式配置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配置
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配置
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)中引用该配置文件中的属性变量
- 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表达式
十五.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)
(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修改
(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 cars = new HashMap();
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
(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 cars = null;
public InstanceFactory()
{
cars = new HashMap();
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)
(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
*/
public class CarFactoryBean implements FactoryBean {
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中配置自己定义的类
- 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配置
以上目录结构:
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
代码演示点击