Spring——Spring简介、入门、配置 , IoC和DI思想

目录

在这里插入图片描述

Spring系列

  1. Spring — Spring简介、入门、配置 , IoC和DI思想
  2. Spring — IoC核心(基于XML)、DI核心(基于XML)
  3. Spring — 使用IoC和DI模拟注册案例、注解配置IoC和DI
  4. Spring — 静态代理、动态代理、拦截器思想
  5. Spring — AOP思想、AOP开发、Pointcut语法、注解配置AOP
  6. Spring — DAO层、Spring JDBC、Spring事务控制
  7. Spring — XML配置事务、注解+XML、纯注解的配置方式
  8. Spring整合MyBatis
  9. Spring Java Config — 组件注册相关注解
  10. Spring Java Config — 常用注解

一、丑陋的代码

跳转到目录
代码耦合严重

  • DAO
// DAO接口
public interface UserDao {
    void getUser();
}

// DAO实现类
public class UserDaoMysqlImpl implements UserDao{
    public void getUser() {
        System.out.println("使用MySQL!");
    }
}
public class UserDaoOracleImpl implements UserDao{
    public void getUser() {
        System.out.println("使用Oracle!");
    }
}
  • Service
// Service接口
public interface UserService {
    void getUser();
}

// Service实现类
public class UserServiceImpl implements UserService{

	private UserDao dao = new UserDaoOracleImpl();
    // private UserDao dao = new UserDaoMysqlImpl();
    public void getUser() {
        dao.getUser();
    }
}
  • 测试类
public class MyTest {
    public static void main(String[] args) {
         UserService userService = new UserServiceImpl();
         userService.getUser();
}
  • 输出

在这里插入图片描述
此时如果把UserDao的实现类换成UserDaoOracleImpl ,此时就需要修改UserServiceImpl的源代码, 不符合开闭原则!

开闭原则: 对扩展开放,对修改关闭;

二、Spring简介

跳转到目录
Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring MVC持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架

什么是容器(Container): 从程序设计角度看就是封装对象的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期,如Tomcat就是Servlet和JSP的容器;

Spring 官网:https://spring.io/projects/spring-framework

下载地址: https://repo.spring.io/libs-release-local/org/springframework/spring/

1、 为什么说Spring是一个一站式的轻量级开源框架呢?

跳转到目录

首先轻量级:不是指Spring框架的模块少,数量很轻,而是指Spring框架的非侵入性,即对象可以不必依赖Spring的API类

其次,JavaEE开发可分成三层架构,针对JavaEE的三层结构,每一层Spring都提供了不同的解决技术。

  • WEB层:SpringMVC
  • 业务层:Spring的IoC
  • 持久层:Spring的JDBCTemplate (Spring的JDBC模板,ORM模板用于整合其他的持久层框架)

Spring提供了JavaEE每一层的解决方案,所以也说Spring是JavaEE的全栈式(full stack)框架。

2.、Spring的优点

跳转到目录

  • 方便解耦,简化开发。
    Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护,交给Spring管理。

  • AOP编程的支持
    Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。

  • 声明式事务的支持
    只需要通过配置就可以完成对事务的管理,而无须手动编程。

  • 方便程序的测试
    Spring对Junit4支持,可以通过注解方便的测试Spring程序。

  • 方便集成各种优秀的框架
    Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts2/Hibernate/MyBatis/Quartz等)的直接支持。

  • 降低JavaEE API的使用难度
    Spring对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等)都提供了封装,使这些API应用难度大大降低。

3、Spring的体系结构

跳转到目录
在这里插入图片描述

核心容器

核心容器由 spring-core,spring-beans,spring-context 和 spring-expression(SpEL,Spring表达式语言,Spring Expression Language)等模块组成,它们的细节如下:

  • spring-core:提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

  • spring-beans:提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。

  • spring-context:模块建立在由core和 beans 模块的基础上建立起来的,它以一种类似于JNDI注册的方式访问对象。Context模块继承自Bean模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过Servelet容器)等功能

  • spring-expression:提供了强大的表达式语言,用于在运行时查询和操作对象图。它是JSP2.1规范中定义的统一表达式语言的扩展,支持set和get属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从Spring IoC容器检索对象,还支持列表的投影、选择以及聚合等。

三、IoC和DI思想

跳转到目录
在这里插入图片描述

  • IoC : Inversion of Control (控制反转), 其本意就是将原本在程序中手动创建对象的控制权,交给Spring来管理;

1、在没有IoC之前,我们的操作是: 若调用者需要使用某个对象,其自身就得负责该对象及该对象所依赖对象的创建和组装;

在这里插入图片描述
2、有IoC之后,调用者只管负责从Spring容器中获取需要使用的对象,不关心对象的创建过程,也不关心该对象依赖对象的创建以及依赖关系的组装;也就是把创建对象的控制权反转给了Spring框架.在这里插入图片描述

  • DI: Dependency Injection(依赖注入)从字面上分析:IoC :指将对象的创建权,反转给了Spring容器;DI : 指Spring创建对象的过程中,将对象依赖属性(常量,对象,集合)通过配置设值给该对象。

    IoC从字面意思上很难体现出谁来维护对象之间的关系, Martin Fowler提出一个新的概念一- -DI ,更明确描述了“被注入对象 ( Service对象)依赖IoC容器来配置依赖对象( DAO对象)" .

在这里插入图片描述

四、 Spring初体验

跳转到目录
1、首先导入Maven坐标

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>

2、HelloSpring类

import lombok.Data;

@Data
public class HelloSpring {
    private String str;
    private int age;
}

3、在resources中创建配置文件,命名为: applicationContext.xmlbeans.xml都行

<?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="helloSpring" class="com.sunny.domain.HelloSpring">
        <property name="str" value="sunny"/> <!--对应HelloSpring中的setStr方法-->
        <property name="age" value="22"/>    <!--对应HelloSpring中的setAge方法-->
    </bean>

</beans>

4、测试类

public class HelloTest {

    @Test
    public void test2(){

        HelloSpring helloSpring = null;

        // 方式一: 官方推荐
        // 获取ApplicationContext: 拿到Spring容器
        /*
			底层实际是采用的工厂设计模式:
			1. 首先通过ApplicationContext("applicationContext.xml")来创建一个context工厂
			2. 通过工厂的getBean方法, 根据id为helloSpring来拿到其全限定类名, getBean方法内通过Class.forName()反射的方式创建该类型的对象
		*/
       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       helloSpring = (HelloSpring) context.getBean("helloSpring");

        // 方式二:
        /*//1. 从classpath去找配置文件,创建资源对象
        Resource resource = new ClassPathResource("applicationContext.xml");
        //2. 根据资源对象,创建Spring IoC容器对象
        BeanFactory factory = new XmlBeanFactory(resource);
        //3. 从Spring IoC容器中获取指定名称(helloSpring)的对象
        helloSpring = factory.getBean("helloSpring", HelloSpring.class);*/

        System.out.println(helloSpring);
    }
}

在这里插入图片描述

  • ClassPathXmlApplicationContext 默认加载classpath路径下的文件,只需指明对应文件的classpath路径下的配置文件名字即可。

  • FileSystemXmlApplicationContext : 该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。

  • WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。

  • 面向接口编程:返回 ApplicationContext (实际上ApplicationContext是一个接口), 即 Spring 的 IOC容器

  • ConfigurableApplicationContext 子接口, 提供了一些方法 close(), refresh(), 可以让 ApplicationContext 刷新和关闭。

在这里插入图片描述

什么是BeanFactroy?

跳转到目录
上面代码写了两种创建Spring IoC容器的办法,下面介绍一下第二种;

  • BeanFactory是Spring最古老的接口,表示Spring IoC容器,生产bean对象的工厂, 负责配置,创建和管理bean
  • 被Spring IoC容器管理的对象称之为bean;
  • Spring IoC容器如何知道哪些是它管理的对象; 此时就需要配置文件,IoC容器读取配置文件的元数据,通过元数据对应用的各个对象进行实例化及装配.
  • 元数据配置的三种方式
    XML-based configuration
    Annotation-based configuration
    Java-based configuration

在这里插入图片描述

首先要分辨BeanFactory 与 FactoryBean的区别,他们两个名字很像,所以容易搞混

  • BeanFactory: 以Factory结尾,表示它是一个工厂类,是用于创建/管理Bean的一个工厂
  • FactoryBean:以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的Id从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身, 如果要获取FactoryBean对象,可以在id前面加一个&符号来获取。(一些复杂对象通过FactoryBean来创建)
  • 为什么返回的不是FactoryBean本身, 因为在Spring容器实现返回给我们的对象是一个代理对象, 在BeanPostProcessor中会对原始对象进行加工处理, 然后返回给我们
Spring IoC管理bean的原理 (工厂设计模式)

跳转到目录

  1. 通过Resource对象加载配置文件
  2. 解析配置文件,得到指定名称的bean
  3. 解析bean元素, id作为bean的名字, class用于反射得到bean的实例;
    注意: 此时bean类必须存在一个无参数构造器(和访问权限无关)
  4. 调用getBean方法的时候, 从容器中返回对象的实例;

在这里插入图片描述

使用getBean方法,从容器中返回对象实例的三种方式:

  • 签名1: Object getBean (String beanName); // 根据bean对象在容器中的名称来获取

    helloSpring = (HelloSpring) factory.getBean(“helloSpring”);

  • 签名2: <T> T getBean(Class<T> requiredType) // 按照指定的类型去寻找bean对象

    helloSpring = factory.getBean(HelloSpring.class); // HelloSpring只能对应一个Bean,多个Bean的时候就会报错

  • 签名3: <T> T getBean(String name,@Nullable Class<T> requiredType): 根据bean的类型 + ID 去寻找.

    helloSpring = factory.getBean(“helloSpring2”, HelloSpring.class);

在这里插入图片描述

Spring的配置文件管理

跳转到目录

  • <import resource=" "/>
    当在Spring的配置文件 applicationContext.xml中配置很多的bean就会很不好管理.在开发中,随着应用规模越来愈大, 该文件中就变得特别臃肿; 为了提高可读性,我们可以将一个applicationContext.xml文件分解为多个配置文件,然后在applicationContext.xml中使用<import resource=" "/>来包含其他的配置文件即可!

  • 语法
    applicationContext.xml文件中导入

    <import resource="classpath:xmls/helloSpring.xml"/>
    

然后helloSpring.xml专门为了生成指定类对象的容器配置文件;
注意: 只有当框架实现了Resource接口才能够使用classpath前缀标识符

Spring的测试框架

跳转到目录

  • 普通的单元测试
    在这里插入图片描述
    存在的问题:
    1、每次测试都要重启Spring,启动容器的开销大,测试效率低
    2、不应是在测试代码管理Spring容器, 应该是在Spring容器在管理测试代码
    3、普通的单元测试不能正常关闭Spring容器,Spring容器声明周期非正常退出(后面会给出验证)
Spring Test框架

在这里插入图片描述
1、使用Spring的测试框架
导入Maven依赖

<!--https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-test</artifactId>
	<version>5.2.2.RELEASE</version>
</dependency>

2、基于junit4的测试
其中: @Autowired注解, 表示从Spring IoC容器中根据类型找到对应的bean,并自动注入到某个字段上

// 下面两个注解: 就表示使用了SpringJunit4的测试方式; @ContextConfiguration注解
// 就替代了之前我们普通测试里面写的代码:加载applicationContext.xml文件
// 配置该注解后, 才可以通过@Autowired来将配置文件中的person对象注入进来
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringJunit4 {

    // @Autowired:表示从Spring IoC容器中根据类型找到对应的bean,并自动注入到某个字段上
    @Autowired
    private Person person;
    
    @Test
    public void test(){
        System.out.println(person);
    }

3、基于junit5的测试

@SpringJUnitConfig
public class SpringJunit5{
	@Autowired
	private Person peroson;
	
	@Test
	void test1(){
		System.out.println(person);
	}
}

五、 解决丑陋代码

跳转到目录

  • DAO 代码不变
  • Service
public interface UserService {
    void getUser();
}

public class UserServiceImpl implements UserService{

    private UserDao dao;

    // 利用set进行动态实现值的注入! // DI注入, 底层本来就是调用的setter方法来设置
    public void setUserDao(UserDao dao){
        this.dao = dao;
    }

    public void getUser() {
        dao.getUser();
    }
}
<?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="mysqlImpl" class="com.sunny._01_static_proxy.dao.UserDaoMysqlImpl"/>
    <bean id="oracleImpl" class="com.sunny._01_static_proxy.dao.UserDaoOracleImpl"/>

    <!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
    <!--引用另外一个bean , 不是用value 而是用 ref-->
    <bean id="serviceImpl" class="com.sunny._01_static_proxy.service.UserServiceImpl">
        <property name="userDao" ref="oracleImpl"/>
    </bean>

</beans>
  • 测试类
public class MyTest {
    public static void main(String[] args) {
    
        // 创建Spring IoC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("serviceImpl");
        serviceImpl.getUser();
    }
}
  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

white camel

感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值