Spring是一个开源框架。
Spring为简化企业级开发而生,使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能。同样的功能,在EJB中要通过繁琐的配置和复杂的代码才能够实现,而在Spring中却非常的优雅和简洁。[EJB是Enterprise Java Beans技术的简称, 又被称为企业Java Beans]
Spring是一个IOC(DI)和AOP容器框架
一句话总结就是:Spring是分层的JavaSE/EE应用full=stack轻量级开源框架.
(1)、方便解耦、简化开发
通过Spring提供的IOC容器,我们可将对象之间的依赖关系交由Spring进行控制,避免了硬编码所造成的过度程序耦合,有了Spring,用户不必在为实现单例、属性文件解析等这些需求而编写代码,可以使开发者更加关注上层应用开发。
(2)、AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程。
(3)、声明式事务的支持
在Spring中,我们可以通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
(4)、方便程序的测试
Spring对Junit4支持,可通过注解方便的测试Spring程序
(5)、方便集成各种优秀的框架
Spring不排斥各种优秀的开源框架,Spring可以降低各种框架的使用难度。
耦合性(Coupling):也叫耦合度,是对模块间关联程度的度量。
从这个框架我们可以看出,Spring主要做的事情是集成,将其他东西集成进来成为一个整体。
IOC(Inversion Of Control)控制反转,Spring反向控制应用程序所需要使用的外部资源
Spring控制的资源全部放置在Spring容器中,该容器称为IOC容器
Spring控制了资源,我们创建对象从主动创建到被动使用,由Spring提供给我们
1、创建Maven工程,导入Spring坐标
2、模拟业务层与表现层,抒写接口和实现类
3、建立Spring配置文件,配置放在IOC容器的资源
4、测试数据
导入Spring5.x依赖
org.springframework
spring-context
5.1.9.RELEASE
创建持久层层接口、接口实现类
/**
* 持久层接口
*/
public interface UserDao {
/**
* 保存数据
*/
public void save();
}
/**
* 持久层接口实现类
*/
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("UserDaoImpl 持久层保存数据");
}
}
创建业务层接口、接口实现类
/**
* 业务层接口
*/
public interface UserService {
public void save();
}
/**
* 业务层接口实现类
*/
public class UserServiceImpl implements UserService {
// 传统的话,我们需要 UserDao userDao = new UserDaoImpl();
// new的方式实例化对象,现在我们使用Spring,对象实例的操作交给Spring,我们只需要声明成员变量就可以了
// 将对象的管理权力交给Spring
private UserDao userDao;
/**
* 提供set方法,等下我们要注入依赖
*/
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
spring的配置文件一般命名为:applicationContext.xml
下面是Spring5.1.9的文档支持,在这里可以找到xml标签格式以及约束
Core Technologies
创建UserTest测试类
/**
* 测试数据
*/
public class UserTest {
public static void main(String[] args) {
// 1、使用上下文程序对象ApplicationContext加载配置文件
// 因为ApplicationContext是接口,所以用实现类ClassPathXmlApplicationContext来实例化对象
// 参数传入Spring配置文件的名称
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2、获取定义的bean资源,根据id ,第二个参数是返回的类型
UserService userService = applicationContext.getBean("userService", UserService.class);
// 3、使用对象执行方法
userService.save();
}
}
执行结果
接下来我们对上面迷惑的知识点进行解读!
基于上面的环境,我们将userService的bean的scope修改为singleton,看下创建的对象地址
测试
/**
* 测试数据
*/
public class UserTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
UserService userService1 = applicationContext.getBean("userService", UserService.class);
UserService userService2 = applicationContext.getBean("userService", UserService.class);
System.out.println(userService);
System.out.println(userService1);
System.out.println(userService2);
}
}
测试结果,创建的地址都相同,单例模式
当我们将scope修改为prototype多例的,看看测试结果
测试结果:对象地址都不同。多例模式
bean的生命周期属性有:init-method、destory-method,定义bean对象在初始化或销毁时候完成的工作
1、我们在UserServiceImpl业务层接口实现类编写init初始化方法和destory销毁方法
2、在bean标签指定初始化方法
3、测试
/**
* 测试数据
*/
public class UserTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.save();
}
}
测试结果:destory没有执行,对象实例化后在执行init方法
由于程序执行的太快,destory方法执行的时候虚拟机就已经结束了,所以使用ClassPathXmlApplicationContext对象强制关闭容器
添加这两行代码,容器关闭交由Spring控制,即可调用销毁方法
细节
在默认情况下,它会根据默认无参数构造方法来创建类对象
如果bean中没有默认无参数构造方法,将会创建bean失败
测试
我们将业务层接口实现类的无参数构造方法替换成有参数,我们在测试数据
我们在业务层接口实现类写有参数构造方法,不写无参数构造方法【依托之前代码】
测试数据
/**
* 测试数据
*/
public class UserTest {
public static void main(String[] args) {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.save();
}
}
测试结果
会报BeanInstantiationException 异常,提示No default constructor found;没有发现默认的构造方法
所以我们在默认使用默认无参数构造方法实例化对象的时候,需要给出无参数构造方法
解决方案:给出无参数构造方法
测试结果
执行成功
使用staticFactory静态工厂类中的静态方法createUserService创建对象,并存入Spring容器
1、创建静态工厂类
创建静态工厂类
/**
* 静态工厂
* 提供静态方法实例化对象
*/
public class UserServiceStaticFactory {
public static UserService getUserService() {
return new UserServiceImpl();
}
}
2、编写bean,将UserServiceImpl接口实现类的class指向改为工厂,然后使用factory-method工厂方法属性指向静态方法
这个了解不太深,大家了解即可
实例工厂用的是普通方法
public class UserServiceFactory2 {
public UserService getUserService() {
System.out.println("实例工厂创建对象执行了......");
return new UserServiceImpl();
}
}
编写bean
这个了解不太深,大家了解即可
DI(Dependency Injection)依赖注入,应用程序运行依赖的资源由Spring为其提供,资源进入应用程序的方式称为注入
DI依赖注入和IOC控制反转相伴而行
IOC(Inversion Of Controller)控制反转,Spring反向控制应用程序所需要使用的外部资源
依赖注入和控制反转是在不同的角度看的,但是发生是同时发生的
在Spring角度上看是IOC模式
在应用程序角度看是DI模式
依赖指的就是Bean实例中的属性,依赖(属性)分为:简单类型(8中基本类型和String类型)的属性、POJO类型的属性、集合数组类型的属性
我们的程序在编写过程中,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。
如果一个bean实体类中包含了一些属性,那么Spring帮我们实例化了bean对象之后,也需要将对应的属性信息进行赋值操作,这种属性赋值操作,就是所谓的依赖注入(获取值,注入属性)
set方法注入(重要)构造方法注入(次要)
手动装配方式(XML方式)
1、需要配置bean标签的子标签property
2、需要配置的bean中指定setter方法
1、创建Maven工程,导入Spring-context上下文依赖
2、模拟业务层接口和业务层接口实现类以及持久层接口和持久层接口实现类
/**
* 持久层接口
*/
public interface UserDao {
public void save();
}
----------------------------------
/**
* 持久层接口实现类
*/
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("持久层保存数据成功!!");
}
}
------------------------
/**
* 业务层接口
*/
public interface UserService {
public void save();
}
----------------------
/**
* 业务层接口实现类
*/
public class UserServiceImpl implements UserService {
/**
* 提供私有属性
*/
private UserDao userDao;
/**
* 提供set方法
*/
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
3、编写配置文件,通过set方法注入业务层接口实现类的dao对象
【注意:属性必须为私有属性,然后提供它的set方法,在bean的name属性填写setXxxXX 的set后面的英文,第一个字母小写】
property属性解读:
name:对应bean中的属性名,要求该属性必须提供可访问的set方法
value:设定非引用类型对应的值,不能与ref同时使用
ref:设定引用类型对应的bean的id,不能与value同时使用
4、测试数据
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.save();
}
}
测试结果:持久层对象实例化成功,调用方法成功
使用类中的构造方法,给成员变量赋值。赋值的操作用过配置的方式,让Spring给属性注入数据
在bean标签下使用constructor-arg标签
格式:
1、修改业务层接口实现类,注入基本数据类型和引用类型
/**
* 业务层接口实现类
*/
public class UserServiceImpl implements UserService {
/**
* 引用数据类型
*/
private UserDao userDao;
/**
* 基本数据类型
*/
private String username;
private int age;
/**
* 提供无参数构造方法
*/
public UserServiceImpl() {
}
/**
* 提供有参数构造方法
* 将要注入的数据通过形参指名
*/
public UserServiceImpl(UserDao userDao, String username, int age) {
this.userDao = userDao;
this.username = username;
this.age = age;
}
@Override
public void save() {
userDao.save();
System.out.println("username:"+username);
System.out.println("age:"+age);
}
}
2、修改Spring配置文件的bean标签
constructor-arg标签属性解读
index:指定参数在构造函数参数列表的索引位置
name:指定参数在构造函数中的名称
value:它能赋的值是基本数据类型和String类型
ref:它能赋的值是其他bean类型,必须的是配置文件中配置过的bean
3、测试,测试成功
本质上还是调用set方法
1、在配置文件引入p名称空间
xmlns:p="http://www.springframework.org/schema/p"
2、使用p名称的空间的语法
基本数据类型 p:属性名 = "值"
引用类型: p:属性名-ref = "值"
在UserServiceImpl提供set方法
/**
* 业务层接口实现类
*/
public class UserServiceImpl implements UserService {
/**
* 引用数据类型
*/
private UserDao userDao;
/**
* 基本数据类型
*/
private String username;
private int age;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setUsername(String username) {
this.username = username;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void save() {
userDao.save();
System.out.println("username:"+username);
System.out.println("age:"+age);
}
}
修改bean,使用p属性
3、测试数据,测试成功
首先我们在UserDao定义属性,提供对应的set方法
/**
* 持久层接口实现类
*/
public class UserDaoImpl implements UserDao {
/**
* 定义集合
*/
private ArrayList arrayList;
/**
* 定义Properties集合
*/
private Properties properties;
/**
* 定义数组
*/
private int[] arr;
/**
* 定义set集合
*/
private HashSet hashSet;
/**
* 定义Map集合
*/
private HashMap hashMap;
// 提供对应的set方法
public void setArrayList(ArrayList arrayList) {
this.arrayList = arrayList;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setArr(int[] arr) {
this.arr = arr;
}
public void setHashSet(HashSet hashSet) {
this.hashSet = hashSet;
}
public void setHashMap(HashMap hashMap) {
this.hashMap = hashMap;
}
@Override
public void save() {
System.out.println("持久层保存数据成功!!");
// 输出集合的数据
System.out.println("List单列集合:"+arrayList);
System.out.println("Properties集合:"+properties);
System.out.println("数组:"+arr);
System.out.println("Set集合:"+hashSet);
System.out.println("Map集合:"+hashMap);
}
}
List1
List2
List3
List4
1
2
3
4
梅州
非常漂亮
set1
set2
set3
set4
测试数据,成功注入数据