springIOC(注解开发、整合junit)

我们先来了解一下程序的耦合和解耦
耦合:程序之间的依赖关系,包括类之间的依赖,方法之间的依赖,独立性很差。
解耦:降低程序间的依赖关系
实际开发中应该做到:编译期不依赖,运行时才依赖
解耦的思路
第一步:使用反射来创建对象,而避免使用new关键字,(一个依赖于具体的驱动类,DriverManager.registerDriver(new com.mysql.jdbc.Driver())如果没有这个jar包,编译就通不过,编译报错。另一个只是依赖于一个字符串Class.forName("com.mysql.jdbc.Driver")
第二步:通过读取配置文件,来获取要创建的对象全限定名。
bean在计算机英语中有可重用组件的含义。javabean是用java语言编写的可重用的组件,javabean > 实体类。使用工厂,创建bean对象,他就是创建我们的service和dao对象的,
第一步:需要一个配置文件来配置我们的service和dao,
第二步:通过读取配置文件中配置的内容,反射创建对象。

开始实例操作,创建工厂,在工厂中编写:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
运行结果为:打印出了五个新的对象,对象被创建多次,执行效率没有单例对象高:
在这里插入图片描述
进行修改重新编写BeanFactory,
在这里插入图片描述
在这里插入图片描述
打印结果:对象只有一个实例的情况下,对值进行了反复的操纵。只被创建了一次,从而类中的成员也就只会初始化一次。使用单例对象效果会更好。。
在这里插入图片描述
小注意PS:
在这里插入图片描述
在这里插入图片描述
通过工厂来控制资源,,提供资源给APP

在学习spring之前先了解几个概念:
(1)什么是bean:其实就是一个java实例对象,是由spring帮你new出来的,并给它其了个名字叫做bean。(通俗)
(2)什么是spring容器:Spring容器是spring框架的核心,是用来管理对象的。容器将创建的对象,把他们连接在一起,配置他们,并管理他们的整个生命周期从创建到销毁。从代码上讲容器就是实现了ApplicationContext接口的类的实例。就是一个ApplicationContext的一个实例化对象。(易懂)
(3)Spring容器类型
Spring提供了两种不同的类型的容器
Spring BeanFactory容器:它是最简单的容器,给 DI 提供了基本的支持
ApplicationContext容器 :ApplicationContext 容器继承自BeanFactory,它包括 BeanFactory 容器的所有功能,所以通常建议使用。
(4)bean标签配置的含义
spring容器会通过读取class属性中的全限定类名,然后通过ClassforName()来反射创建出一个对象实例,再通过id把它取出来。

https://blog.csdn.net/qq_34598667/article/details/83245753
https://blog.csdn.net/weixin_43277643/article/de

接下来我们开始进入Spring框架

IOC控制反转:
把创建对象的权力交给spring来实现,他包括依赖注入和依赖查找。
降低程序之间的耦合,但并不能消除。
从现阶段来说,我们只需要降低他们之间的依赖关系就可以,自己写代码可以使用工厂模式来实现。把这个工厂模式交给Spring来实现。

以上是使用了工厂模式

章节:使用spring的IOC降低程序耦合!
作用:只能解耦,降低程序之间的依赖关系
使用配置的方式,来实现上一次的工厂开发模式。。
spring的核心容器其实就是一个封装的map。
在这里插入图片描述
在这里插入图片描述

ApplicationContext三个常用实现类
在这里插入图片描述
ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径在。用于加载classpath(类路径、src)下的xml
加载xml运行时位置 --> /WEB-INF/classes/…xml
FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)。用于加载指定盘符下的xml
加载xml运行时位置 --> /WEB-INF/…xml

在这里插入图片描述
AnnototionConfigAplicationContext:他是用于读取注解创建容器的。
在调试时:光标停到的位置说明还没有走。

核心容器的两个接口引发的问题:
两个接口创建对象的时间点是不一样的
(1)ApplicationContext:它在构建核心容器时,创建对象采取的策略是立即加载的方式,(只要一读取完配置文件,就马上就创建配置文件中配置的对象,利用反射机制创建出来)
操作演示:
适用于:单例对象。
在这里插入图片描述
一读完配置文件,对象马上就被创建了。如下:
在这里插入图片描述
(2)BeanFactory:他在构建核心容器时,创建对象采取的策略是延迟加载的方式(什么时候根据id获取对象了,什么时候才真正的创建对象)什么时候用什么时候才会创建。
适用于:双例对象,因为如果我们在一加载容器时就把对象创建出来,那我们载用肯定又要创建第二次了,所以我们还是应该什么时候用就什么时候创建比较好。
在这里插入图片描述
什么时候适合立即加载\延迟加载?
在工厂模式解耦时,无论是Service还时dao,因为没有类成员,所以不会有线程安全问题,所以我们可以直接使用单例模式来创建Service和dao。
BeanFactory是一个顶层接口,可能不太完善,他的子接口会在他的基础上进行一个扩展延申。所以在实际开发中更多的是采用ApplicationCaontext接口来定义容器对象

Spring中的三种细节,以及三种创建bean对象的方式
1.创建bean的三种方式
第一种方式,使用默认构造函数创建
在spring的配置文件中使用bean标签,配置id和class属性,且没有其他属性和标签时。
这种方式是采用的就是默认构造函数创建bean对象,此时,如果类中没有默认构造函数,则对象无法创建,应用如下:
在这里插入图片描述
在这里插入图片描述
所以说我们在bean标签里面只写id和class,spring默认就会去找类中的默认构造函数,如果自己创建了构造函数,默认的就会实现,无法实现其功能。

在实际开发中我们可能会用到一些别人写好的类,可能是存在于jar包中的,存在jar包的文件都是字节码文件,所以我们不能够修改。
第二种方式:使用实例工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器中),如下:
在这里插入图片描述
在这里插入图片描述
第三种方式,使用工厂中静态方法创建对象(也可以说使用某类中的静态方法创建对象,并存入spring容器),如下:
在这里插入图片描述
在这里插入图片描述
因为我们在使用的一些jar包类中方法有可能是静态有可能是非静态的。spring 支持这种配置。

bean的作用范围
在这里插入图片描述
bean的作用范围调整
bean标签的scop属性 作用:用于指定bean的作用范围
取值:singleton 单例的(默认值)
prototype: 多例的
request:作用域web应用的请求范围
session:作用于web应用的会话范围
global-session: 作用于集群环境的会话范围(全局会话范围)当不是集群环境是,他就是session

bean对象的生命周期:
单例对象:单例对象的生命周期和容器同步
操作应用:
在这里插入图片描述
在这里插入图片描述
没有打印出对象销毁的原因是:main方法是程序的执行入口,当main方法执行结束以后,我们当前应用的占用的线程内存被全部释放。当然也是包含容器在内的,但是此时并没有调用销毁方法,就把内存全部释放了,所以说还没来得及调用销毁就结束了。
在这里插入图片描述
但是对于多例的对象,即使close()了也不会去调用销毁方法,原因
多例对象:是当我们使用对象时,Spring框架为我们创建。
对象只要是在使用中就是一直活着的。当对象长时间不用,且没有别的对象使用时,由java垃圾回收器回收。
在这里插入图片描述
spring框架是一个很强大的框架配置这个对象是单例还是多例,从而来为我们设定什么时候去创建对象,对象创建的时机是立即还是延迟。

Spring的依赖注入:
spring的依赖注入
依赖注入:dependence Injection
IOC的作用:降低程序之间的耦合关系
依赖关系的管理:以后都交给了spring来维护,
当前对象需要其它类的对象,由spring为我们提供,我们只需要在配置文件中说明
依赖关系的维护,就称之为依赖注入
依赖注入:
能注入的数据:有三类
基本类型和String
其他bean类型(在其他配置文件中或者注解配置过的bean)
复杂类型/集合类型
注入的方式:有三种:
第一种:使用构造函数提供
第二种:使用setter方法提供
第三种:使用注解提供
(1)构造函数注入 (不常用)
构造函数注入
使用的标签:constructor-arg
标签出现的位置:bean标签的内部
标签中的属性:
type: 用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型。
index:用于指定注入的数据给构造函数中指定索引位置的参数赋值,参数索引的位置是 从0开始
name:用于指定给构造函数中指定名称的参数赋值 (常用)
=以上三个属性用于给构造函数中那个参数赋值===
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据,他指的是在SpringIOC核心容器中出现过的bean对象通过bean标签或者注解配置过的,就可以引用。
在这里插入图片描述
value:用于提供基本类型和String类型的数据,不能提供日期类的,需要自己定义。如下:
在这里插入图片描述
在这里插入图片描述
优势:在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功
弊端:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。

(2)set方法注入:(常用)
涉及的标签:propery
出现的位置:bean标签的内部
标签的属性:
name:用于指定注入时所调用的set方法名称,把方法名的set去掉大写改小写
value:
ref:
优势:创建对象时,没有明确的限制,可以直接使用默认构造函数。
弊端:如果某个成员必须有值,则获取对象时有可能set方法没有执行。
操作-在实现类里面添加set方法:
在这里插入图片描述
在这里插入图片描述
注入集合数据(复杂类型)
用于给list结构集合注入的标签: List,arrey,set
用于给Map结构集合注入的标签:map,props
结构相同,标签可以互换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
PS:后面的两个就不些啦!自己操作一下就会了!
在这里插入图片描述

=========================================
Spring基于注解的Ioc及Ioc案例

springIoc中的常用注解

  • 用于创建对象的注解
  • 他们的作用就是和在XML的配置文件中编写的bean标签实现功能一样
    
  •  @Component :
    
  • 用于注入数据的,
  • 作用就和配置文件中的bean标签里面的<property>标签实现的作用一样
    
  • 用于改变作用范围的:
  • bean标签里面的scope属性
    
  • 和生命周期相关–了解
  • bean标签的init-method和destory-method实现的功能一样
    

操作演示:
@component
用于把当前类对象存入spring容器中,属性value用于指定bean的id,如果不写,默认是当前类字母改小写 @Controller:一般在表现层 @Service:一般在业务层
@Repository:一般在持久层
以上三个注解与conmpent作用是一样的,他们三个是spring框架为我们提供明确三层使用的注解,是我们的三层对象更加清晰

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
PS:报空指针异常,因为userDao对象是null
在这里插入图片描述
@Autowired
用于按照类型注入,
只要容器中有唯一的个bean对象类型和要注入的变量类型匹配,就可以注入成功。
如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则会报错。

  •   出现的位置可以是变量,也可以是方法上
    
  •   细节:使用注解注入时set方法就不是必须的了
    

在这里插入图片描述
运行成功:
在这里插入图片描述
PS:spring的IOC容器:是一个Map结构的
Map(key-value)的结构:
当有多个时,要更改类成员变量名称和注解里面的value一致才可以。
在这里插入图片描述在这里插入图片描述
@Qualifier
在按照类中注入的基础上再按照名称注入,他在给类成员注入时不能单独使用。但给方法参数注入时可以,属性value用于指定bean的id,
注:不能单独使用,再给类成员注入时要和Autowired配合使用。
在这里插入图片描述
@Resource:
可以直接按照bean的id注入,可以独立使用
但是它的属性不再是value而是name属性
在这里插入图片描述
以上三个注入都是只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能使用xml来实现。
@value
用于注入基本类型和String类型的数据,属性value用于指定数据的值,同时它可以使用spring中的SpEl(spring的EL的表达式)
SpEL的写法:${表达式}
用于改变作用范围的:
@Scope
用于指定bean的作用范围的
属性value指定范围取值,常用取值singleton,prototype
默认是使用单例的,
在这里插入图片描述
和生命周期相关–了解
@PreDestroy
用于指定销毁方法
@PostConstruct
用于指定初始化方法
多例对象销毁,spring容器是不会负责的,长期不用,JVM会进行垃圾回收。
在这里插入图片描述
基于bean.xml的SpringIoc案例
在这里插入图片描述

在这里插入图片描述
runner属性也需要注入
QueryRunner" scope=“prototype”,默认是单例,单例会产生线程安全问题。。

spring的新注解
@ Configuration:
作用:指定当前类是一个配置类
细节:当配置类作为AnnotationApplicationContext对象创建的参数时,该注解可以不写。
但不是什么时候都可以不写的:
在这里插入图片描述

@ ComponentScan
作用:用于通过注解指定spring容器在创建容器时需要扫描的包
属性:value和basePackages的作用时一样的,都是用于指定创建容器时要扫描的额包 我们使用此注解,就等于再xml中配置了<context:component-scan base-package=“com.selan”></context:component-scan>
basePackages的值一定要是类路径在这里插入图片描述
spring的新注解@Bean
在这里插入图片描述
作用:用于把当前方法的返回值作为bean对象,放入springIOC容器中。
细节:当我们使用注解配置方法时,如果方法有参数,spring框架会从容器中查找有没有可用的bean对象

  •      查找的方式和@Autowire注解的作用是一样的(自动按照类型匹配注入)
    

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
字节码可变参数类型的componentClass指被注解的类。

解决QueryRunner单例问题
本应该是多例的,
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
@Import
作用:用于导入其他的配置类
属性 value:用于指定其他配置类的字节码
当我们使用import注解后,有import注解的类就是父配置类(SpringConfiguration),而导入的都是子配置类
在这里插入图片描述
一下这些就都不用了:
在这里插入图片描述
**@Properties:**用于指定properties文件的位置
属性:value指定文件的名称和路径com/config/…
在这里插入图片描述
在这里插入图片描述
使用全注解的额方式,我举得比使用配置文件的方式还要复杂,不太容易理解。如果能自己选择的话,可以选择既有注解也有xml的方式。那个使用方便就用那种方式。

spring整合Junit
大家都直到程序的执行入口是main方法
junit单元测试种没有main方法也能够执行,其原因是junit集成了main方法,该方法就会判断当前测试了中那些方法有@Test注解,junit就让有test的方法执行。
junit不会管我们是否使用了框架,在执行测试方法时,junit根本不知道我们时不是使用了spring框架,所以也就不会为我们读取配置文件信息/配置类为我们创建spring核心容器。
所以有以上可知,当测试方法执行时,没有IOC容器,就算写了@Autowire也不能实现:如下可以看到:
初始值为null,产生空指针
在这里插入图片描述
整合junit配置空指针解决
1.导入spring整合junit的jar包(坐标)
在这里插入图片描述
2.使用junit提供的一个注解,把原有的main方法替换,替换成spring中的
@Runwith 运行器,就是带有main方法的函数类

3.告知spring是基于xml的还是注解的,
@ContextConfiguration
属性:locations:指定xml文件配置,加上classpath关键字,表示在类路径下。
classes:指定指定注解类所在的位置,并说明位置。
细节:当我们使用spring使用5版本的时候,需要junit的jar包必须是4.12以上。
测试代码如下:
/**

  • 使用Junite进行单元测试

*1.导入spring整合junit的jar包(坐标)

*2.使用junit提供的一个注解,把原有的main方法替换,替换成spring中的@Runwith运行器,就是带有main方法的函数类

*3.告知spring是基于xml的还是注解的,并说明位置
@ContextConfiguration
属性:locations:指定xml文件配置,加上classpath关键字,表示在类路径下
classes:指定指定注解类所在的位置。
*/


//SpringJUnit4ClassRunner这个类就是继承junit中的Runner
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes =SpringConfiguration.class)
public class Test01 {
    @Autowired
    private ApplicationContext applicationContext;
    private IAccountService accountService;
    @Before
    public void init(){
        //1.获取spring容器
        applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class,JdbcConfig.class);
        //2.得到业务层对象
        accountService = applicationContext.getBean("accountService",IAccountService.class);
    }

    @Test
    public void findAll() {
        List<Account> accounts = accountService.findAll();
        for(Account account:accounts) {
            System.out.println(account);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值