一、Spring 框架概念、模块划分与环境搭建
1.Spring框架概念
- Spring 是众多开源 java 项目中的一员,基于分层的 javaEE 应用一站式轻量级开源框
架,主要核心是 Ioc(控制反转/依赖注入) 与 Aop(面向切面)两大技术,实现项目在开发过
程中的轻松解耦,提高项目的开发效率。 - 在项目中引入 Spring 立即可以带来下面的好处 降低组件之间的耦合度,实现软件各层
之间的解耦。可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们
使用容器管理事务时,开发人员就不再需要手工控制事务.也不需处理复杂的事务传播。 容
器提供单例模式支持,开发人员不再需要自己编写实现代码。 容器提供了 AOP 技术,利
用它很容易实现如权限拦截、运行期监控等功能。
1.Spring官网
- spring.io
2.版本介绍
- GA:稳定版
- SNAPSHOT:快照版
- Pre:预发布
- Alpha:第一次修正
- Beta:第二次修正
3.什么叫Spring
- Spring是一款企业级开发的开源框架
- Spring提供IOC容器和AOP框架
- IOC解决了对象的创建以及对象管理,同时解决了对象与对象之间的依赖
- AOP解决的是一些公关的业务逻辑
- Spring是一种"粘合剂",采用Spring去集成第三方框架或者组件(MyBatis/Redis客户端/RabbitMQ客户端/Hibernate等等),集成原理还是基于IOC容器
2.Spring组件介绍
- 数据访问相关组件(Data Access):Spring JDBC/Spring ORM/Spring OXM
- Web应用相关组件(Web): Spring Web、Spring MVC(重点)、Spring Websocket…
- AOP(面向切面编程)、Aspects(切面)
- 核心容器组件:Beans(Bean相关内容:BeanFactory)、Context(Spring配置的上下文 ApplicationContext)、Core、SpEL(Spring的EL表达式)
- 测试组件:Spring-test包含:mock(模拟)测试、Random Port(随机端口测试)、TestContext Framework(测试上下文框架)
3.集成Spring框架
- 在项目的pom中添加spring-context依赖,通过Maven的依赖传递将Spring其他核心组件的jar包也一起依赖进项目
<!--依赖Spring相关jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
4.Bean的概念
- <beans…/>元素是Spring配置文件的根元素,<beans…/>元素可以包含多个<bean…/>子元素,每个<bean…/>元素可以定义一个Bean实例,每一个Bean对应Spring容器里的一个Java实例定义Bean时通常需要指定两个属性。
- Id:确定该Bean的唯一标识符,容器对Bean管理、访问、以及该Bean的依赖关系,都通过该属性完成。Bean的id属性在Spring容器中是唯一的。
- Class:指定该Bean的具体实现类。注意这里不能使接口。通常情况下,Spring会直接使用new关键字创建该Bean的实例,因此,这里必须提供Bean实现类的类名。
- Spring容器集中管理Bean的实例化,Bean实例可以通过BeanFactory的getBean(String beanid)方法得到。BeanFactory是一个工厂,程序只需要获取BeanFactory引用,即可获得Spring容器管理全部实例的引用。程序不需要与具体实例的实现过程耦合。大部分Java EE应用里,应用在启动时,会自动创建Spring容器,组件之间直接以依赖注入的方式耦合,甚至无须主动访问Spring容器本身。
- 当我们在配置文件中通过方法配置一个Bean时,这样就需要该Bean实现类中必须有一个无参构造器。
5.构建Spring的一个Bean对象
- 1.编写一个HelloService类,同时创建一个hello()
- 2.创建一个application.xml文件,同时添加beans相关的命名空间,配置HelloService Bean
<?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.xsd">
<!--配置bean 其中id唯一标记这个bean,class属性代表是这个bean的类-->
<bean id="helloService" class="com.shsxt.service.HelloService" />
</beans>
- 3.编写测试代码,测试启动Spring容器,从容器中获取HelloService对象(bean)
第一步:启动容器:创建一个ApplicationContext对象,有两个实现类:ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,传入对应的xml配置文件
第二步:获取bean对象:ApplicationContext中的getBean(id/name, clazz)
第三步:执行bean的方法
/**
* 通过构建一个FileSystemXmlApplicationContext上下文对象(本质是一个ApplicationContext)
*/
public static void getHelloServiceBean01() {
// 启动Spring容器: ApplicationContext是Spring的核心上下文容器
ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:application.xml");
// 获取对象
HelloService helloService = (HelloService) ac.getBean("helloService");
// 执行对象中的方法
helloService.hello();
}
/**
* 通过构建一个ClassPathXmlApplicationContext上下文对象(本质是一个ApplicationContext)
*/
public static void getHelloServiceBean02() {
// 启动Spring容器: ApplicationContext是Spring的核心上下文容器
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:application.xml");
// 获取对象
HelloService helloService = ac.getBean("helloService", HelloService.class);
// 执行对象中的方法
helloService.hello();
}
6.构建Spring的一个Bean对象
-
思路
1.读取xml,解析xml配置(dom4j解析)(解析方式2种:DOM解析–全部读取xml节点到内存,然后进行解析;SAX解析–边读取边解析)
2.获取<bean id=”” class=”” />标签,将bean标签的属性封装到对象中
3.将解析后的标签的对象存入集合中
4.遍历解析后的Bean标签(id, class)集合,同时利用反射机制创建对象,并将id和对象存入map中
5.编写一个getBean(id)的方法获取bean实例化后的对象 -
代码实现
第一步:编写一个BeanFactory,暴露一个getBean接口
/**
* 模拟Bean工程提供获取Bean的方法
*/
public interface BeanFactory {
public Object getBean(String id);
}
第二步:编写BeanFactory的实现类SxtClassPathXmlApplicationContext()
该类包含两个属性:第一个属性存放Map其中key为id, value为实例化后的bean对象;第二个属性就存放bean标签的集合对象
/**
* 模拟的是一个ApplicationContext上下文容器
*/
public class SxtClassPathXmlApplicationContext implements BeanFactory {
private Map<String, Object> beans = new HashMap<>();// 实例化后的对象放入map
private List<SxtBean> sxtBeans;// 存放已读取bean 配置信息
}
第三步:编写一个构造器,传入xml配置文件,调用解析方法进行xml读取、解析,调用实例化对象的方法去实例化对象(应用反射)
// 构造器,传入xml配置文件名
public SxtClassPathXmlApplicationContext(String fileName) {
this.readBeansXml(fileName);// 读取并解析配置文件
this.insranceBeans(); // 实例化bean
}
第四步:读取、解析xml配置文件,将bean标签内容存入集合的SxtBean对象中(bean metadata)
/**
* 读取 并解析xml 配置文件
* @param fileName
*/
private void readBeansXml(String fileName) {
URL url=this.getClass().getClassLoader().getResource(fileName);
// 判断xml配置文件是否存在
if (url == null) {
System.out.println("资源文件未找到!");
return;
}
// 解析xml配置文件
SAXReader saxReader=new SAXReader();// 创建saxReader 对象
Document doc= null;
try {
doc = saxReader.read(url);
} catch (DocumentException e) {
e.printStackTrace(); // 打印异常的堆栈信息
return;
}
Map<String, String> map = new HashMap<>(); // 一定要加泛型
map.put("sxt", "http://www.springframework.org/schema/beans"); //将xml命名空间放入map
XPath xPath= doc.createXPath("//sxt:bean");//定义查找路径
xPath.setNamespaceURIs(map);
List<Element> elements = xPath.selectNodes(doc);
if (CollectionUtils.isEmpty(elements)) {
return;
}
sxtBeans = new ArrayList<>();
for(Element element : elements){
//System.out.println(element.attributeValue("id")+element.attributeValue("class"));
SxtBean sxtBean = new SxtBean(element.attributeValue("id"), element.attributeValue("class"));
sxtBeans.add(sxtBean);
}
}
第五步:遍历bean的元数据信息(SxtBean集合)信息,利用反射实例化对象,同时存储到map中
/**
* 实例化bean 对象
*/
private void insranceBeans() {
// 先判断<bean>标签集合是否有值
if (CollectionUtils.isEmpty(sxtBeans)) {
return;
}
// 遍历<bean>标签,同时利用反射机制生成对象,并将对象存入map中,其中key为bean对象的id,value是对象
for(SxtBean sxtBean: sxtBeans){
try {
beans.put(sxtBean.getId(), Class.forName(sxtBean.getClazz()).newInstance());
} catch (Exception e) {
continue;
}
}
}
第六步:重写getBean方法,从map中返回bean的实例化后的对象
/**
* 根据id 名获取bean
*/
@Override
public Object getBean(String id) {
return beans.get(id);
}
7.IOC容器加载多个配置文件
第一种:启动ApplicationContext上下文容器时,允许加载多个配置文件
@Test
public void testMultiXml() {
// 启动IOC容器(加载配置文件生成ApplicationContext)
ApplicationContext ac = new ClassPathXmlApplicationContext("controller.xml", "dao.xml", "service.xml");
// 获取Bean对象
UserController userController = ac.getBean("userController", UserController.class);
UserService userService = ac.getBean("userService", UserService.class);
UserDao userDao = ac.getBean("userDao", UserDao.class);
// 调用Bean方法
userController.show();
userService.add();
userDao.save();
}
第二种:用某一个公共的配置文件,把其他配置文件通过<import resource=”” />导入进来
<!--配置bean 其中id唯一标记这个bean,class属性代表是这个bean的类-->
<bean id="helloService" class="com.shsxt.service.HelloService" />
<import resource="controller.xml"/>
<import resource="service.xml"/>
<import resource="dao.xml"/>
@Test
public void testSingleXml() {
// 启动IOC容器(加载配置文件生成ApplicationContext)
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
// 获取Bean对象
UserController userController = ac.getBean("userController", UserController.class);
UserService userService = ac.getBean("userService", UserService.class);
UserDao userDao = ac.getBean("userDao", UserDao.class);
// 调用Bean方法
userController.show();
userService.add();
userDao.save();
}
8.Bean的实例化方式
- 第一种是上面写的构造器实例化
- 第二种是静态工厂实例化
**
* 静态工厂实例化Bean
*/
public class StaticFactory {
/**
* 编写一个静态方法,同时返回一个实例化对象
* @return
*/
public static UserService createUserService(){
return new UserService();
}
}
<?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.xsd">
<!--静态工厂实例化Bean,配置的class指向工厂类,添加factory-method属性指向创建对象的静态方法-->
<bean id="userService" class="com.shsxt.factory.StaticFactory" factory-method="createUserService" />
</beans>
- 第三种是实例化工厂方法
/**
* 实例化工厂创建Bean对象
*/
public class InstanceFactory {
/**
* 此方法不需要静态化
* @return
*/
public UserService createUserService() {
return new UserService();
}
}
<?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.xsd">
<!--通过实例化工厂类创建Bean对象-->
<bean id="instanceFactory" class="com.shsxt.factory.InstanceFactory" /> <!--工厂bean-->
<!--实例化UserService Bean-->
<bean id="userService" factory-bean="instanceFactory" factory-method="createUserService" />
</beans>
9.对象依赖与注入
1.IOC本质问题
- IOC:控制反转,就是由原来主动创建对象改成交给spring创建对象
public class UserController {
private UserService userService = new UserService(); // 主动创建
}
public class UserController {
private UserService userService ;
public UserController(UserService userService) { // 交由第三方创建在传入
this.userService = userService;
}
2.依赖注入(DI)
- 依赖:对象与对象之间的关系,注入由第三方(Spring)在实例化对象时进行注入。因此DI是IOC的另外一种表达方式,换个说法:IOC是DI的理论基础
3.依赖注入的方法
- 四种注入方式
- 构造器注入(比较常用)
- setter注入(最常用)
- 静态工厂注入(比较少用)
- 实例工厂注入(比较少用)