Spring(3)IOC及依赖注入(基于注解的实现)

学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样

的,都是要降低程序间的耦合。只是配置的形式不一样。

关于实际的开发中到底使用xml还是注解,每家公司有着不同的使用习惯。所以这两种配置方式我们都需要掌

握。

环境配置

bean.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <!--把对象创建交给spring管理--> <context:component-scan base-package="domain"></context:component-scan>
</beans>

对具体类的配置

package domain.service.impl;

import domain.service.IAccountService;
import domain.dao.IAccountDao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource; @Service("accountService")
@Scope
public class AccountServiceImpl implements IAccountService {
// @Autowired
// @Qualifier("accountDao1")
@Resource(name = "accountDao1")
private IAccountDao accountDao = null; public AccountServiceImpl() {
System.out.println("对象创建成功");
// System.out.println("a = "+ a);
} public void saveAccount() {
accountDao.saveAccount();
} @PostConstruct
public void init() {
System.out.println("初始化。。");
} @PreDestroy
public void destory() {
System.out.println("销毁方法。。");
}
}

1、常用注解

<bean id="accountService" class="domain.service.impl.AccountServiceImpl" scope="singleton" init-method="" destroy-method="">
<property name="" value="" ref=""></property>
</bean>

1.1、用于创建对象的

作用等同于xml配置中的bean标签

<bean id="" class=""></bean>

1.1.1、Component

作用:把被注解的类创建对象后放入spring容器中

属性:

value:指定当前的bean的id,如果不写那么他的默认值是被注解的类的类名,且首字母小写

@Service("accountDao1")
public class AccountDaoImpl implements IAccountDao {
public void saveAccount() {
System.out.println("保存账户成功!!!11111111111");
}
}

1.1.2、Controller,Service,Repository

以上三个注解的作用和属性与Component完全相同,

它们是spring提供的三层架构的注解,使三层对象更加清晰

@Controller :一般用于表现层的注解。

@Service :一般用于业务层的注解。

@Repository :一般用于持久层的注解。

细节:如果注解中有且只有一个属性 要赋值时是 ,且名称是 value ,value 在赋值是可以不写。

1.2、用于注入数据

作用等同于xml中的bean标签下的properties标签

<bean id="" class="">
<property name="" value=""/ref=""></property>
</bean>

1.2.1、@Autowired

作用:自动按照类型注入,只要有唯一的一个bean对象与要注入的类型匹配,就可以注入成功

如果IOC容器中没有与要注入变量同类型的bean,则报错

如果IOC容器中有多个与之类型匹配,在不使用其他注解的情况下,依据要注入变量的名称和bean对象的id进行比较,如果变量名与id相同就可以注入,如果无匹配id则报错

出现位置:

变量和方法上都可以出现

细节:使用注解注入时,set方法非必须

@Autowired
private IAccountDao accountDao = null;

1.2.2、Qualifier:

作用:

在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和

@Autowire 一起使用;但是给方法参数注入时,可以独立使用。

属性:

value:指定 bean 的 id。

@Autowired
@Qualifier("accountDao1")
private IAccountDao accountDao = null;

1.2.3、@Resource

作用:

直接按照 Bean 的 id 注入。它也只能注入其他 bean 类型。

属性:

name:指定 bean 的 id。

@Resource(name = "accountDao1")
private IAccountDao accountDao = null;

1.2.4、@Value

作用:

注入基本数据类型和 String 类型数据的

属性:

value:用于指定数据的值。它可以使用spring中的spEl(spring中的EL表达式)

spEL写法:${表达式}

@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;

1.3、用于改变作用范围的

作用等同于xml配置中bean标签的scope属性

@Service("accountDao1")
@Scope("prototype")
public class AccountDaoImpl implements IAccountDao {
public void saveAccount() {
System.out.println("保存账户成功!!!11111111111");
}
}

1.3.1、 @Scope

作用:

指定 bean 的作用范围。

属性:

value:指定范围的值。

取值:singleton prototype request session globalsession

1.4、改变作用范围

作用等同于xml配置中的init-method和destory-method属性

@PostConstruct
public void init() {
System.out.println("初始化。。");
} @PreDestroy
public void destory() {
System.out.println("销毁方法。。");
}

1.4.1、@PostConstruct

作用:

用于指定初始化方法。== init-method

1.4.2、@PreDestroy

作用:

用于指定销毁方法。==destory-method

1.5、关于 Spring 注解和 XML

注解的优势:

配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。适用于自己定义的类

XML 的优势:

修改时,不用改源码。不涉及重新编译和部署。适用于通过jar导入的类

2、spring 的纯注解配置

写到此处,基于注解的 IoC 配置已经完成,但是大家都发现了一个问题:我们依然离不开 spring 的 xml 配

置文件,那么能不能不写这个 bean.xml,所有配置都用注解来实现呢?

2.1、问题

之所以我们现在离不开 xml 配置文件,是因为我们有一句很关键的配置:

<!-- 告知spring框架在,读取配置文件,创建容器时,扫描注解,依据注解创建对象,并存入容器中 -->
<context:component-scan base-package="com.itheima"></context:component-scan>

如果他要也能用注解配置,那么我们就离脱离 xml 文件又进了一步。

另外,数据源和 JdbcTemplate 的配置也需要靠注解来实现。

<!-- 配置 dbAssit -->
<bean id="dbAssit" class="com.itheima.dbassit.DBAssit">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///spring_day02"></property>
<property name="user" value="root"></property>
<property name="password" value="1234"></property>
</bean>

2.2、新注解说明

2.2.1、@Configuration

作用:

用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用

AnnotationApplicationContext(有@Configuration 注解的类.class)。

属性:

value:用于指定配置类的字节码

细节:当配置类作为AnnotationConfigApplicationContext对象创建容器的参数该注解可以省略

@Configuration
public class SpringCinfiguration { }

注意:

我们已经把配置文件用类来代替了,但是如何配置创建容器时要扫描的包呢?

请看下一个注解。

2.2.2、@ComponentScan

作用:通过注解指定spring容器在创建时要扫描的包

属性:value:和basePackages作用相同,都是指定要创建容器要扫描的包

该注解作用相当于在xml中配置的:

     <context:component-scan base-package="wf"></context:component-scan
@Configuration
@ComponentScan(basePackages = {"wf","config"})//wf,config是包名
public class SpringCinfiguration { }

注意:

我们已经配置好了要扫描的包,但是数据源和 JdbcTemplate 对象如何从配置文件中移除呢?

请看下一个注解。

2.2.3、@Bean

作用:把当前方法的返回值作为bean对象存入spring的ioc容器中

​ 属性:

​ name:用于指定bean对象的id,当不写时默认是当前方法名

​ 细节:

​ 当我们使用注解配置方法时,如果方法有参数,sprig框架就会去容器中查找看是否由可用bean对象

查找方式和Autowired注解的作用一样

@Bean(name = "runner")
public QueryRunner creatQueryRunner(@Qualifier("ds1") DataSource dataSource){
return new QueryRunner(dataSource);
}

注意:

我们已经把数据源和 DBAssit 从配置文件中移除了,此时可以删除 bean.xml 了。

但是由于没有了配置文件,创建数据源的配置又都写死在类中了。如何把它们配置出来呢?

请看下一个注解。

2.2.4、@PropertySource

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring
jdbc.username=root
jdbc.password=123456

作用:

用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到

properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。

属性:

value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:

@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
}

注意:

此时我们已经有了两个配置类,但是他们还没有关系。如何建立他们的关系呢?

请看下一个注解。

2.2.5、@Import

作用:用于导入其他的配置类,在引入其他配置类时,可以不用再写@Configuration 注解。当然,写上也没问

题。

属性:

value[]:用于指定其他配置类的字节码。

@Configuration
@ComponentScan(basePackages = {"wf","config"})
@Import({JdbcConfig.class})
public class SpringCinfiguration { }

注意:

我们已经把要配置的都配置好了,但是新的问题产生了,由于没有配置文件了,如何获取容器呢?

请看下一小节。

2.2.6、通过注解获取容器:

AnnotationConfigApplicationContext ca = new AnnotationConfigApplicationContext(SpringCinfiguration.class);

3、Spring 整合 Junit

3.1、问题

在测试类中,每个测试方法都有以下两行代码:

ApplicationContext ac = new ClassPathXmlApplicationContext(“bean.xml”);

IAccountService as = ac.getBean(“accountService”,IAccountService.class);

这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。

3.2、解决思路分析

针对上述问题,我们需要的是程序能自动帮我们创建容器。一旦程序能自动为我们创建 spring 容器,我们就无须手动创建了,问题也就解决了。

我们都知道,junit 单元测试的原理(在 web 阶段课程中讲过),但显然,junit 是无法实现的,因为它自己都无法知晓我们是否使用了 spring 框架,更不用说帮我们创建 spring 容器了。不过好在,junit 给我们暴露了一个注解,可以让我们替换掉它的运行器。

这时,我们需要依靠 spring 框架,因为它提供了一个运行器,可以读取配置文件(或注解)来创建容器。我们只需要告诉它配置文件在哪就行了。

3.3 、 配置步骤

3.3.1、导入相关坐标

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>

3.3.2、使用@RunWith 注解替换原有运行器

@RunWith(SpringJUnit4ClassRunner.class)
public class AccountServiceTest {}

3.3.3、使用@ContextConfiguration 指定 spring 配置文件的位置

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringCinfiguration.class)
public class AccountServiceTest {}

@ContextConfiguration 注解:

locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明

classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。

3.3.4、使用@Autowired

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringCinfiguration.class)
public class AccountServiceTest { @Autowired
private IAccountService as;
}

完整代码

package test;

import config.SpringCinfiguration;
import org.apache.commons.dbutils.QueryRunner;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import wf.domain.Account;
import org.junit.Test;
import wf.service.IAccountService; import java.util.List; /**
* 使用junit进行单元测试
* spring整合junit的配置
* 1.导入spring整合junit的jar
* 2.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringCinfiguration.class)
public class AccountServiceTest { @Autowired
private IAccountService as;
@Test
public void testQuery(){
//1.加载配置文件
AnnotationConfigApplicationContext ca = new AnnotationConfigApplicationContext(SpringCinfiguration.class);
//2.获取服务层对象
QueryRunner as = ca.getBean("runner", QueryRunner.class);
QueryRunner as1 = ca.getBean("runner", QueryRunner.class);
System.out.println(as ==as1); }
@Test
public void testFindAll(){
/* //1.加载配置文件
//, JdbcConfig.class
AnnotationConfigApplicationContext ca = new AnnotationConfigApplicationContext(SpringCinfiguration.class);
//2.获取服务层对象
IAccountService as = ca.getBean("accountService", IAccountService.class);*/
//3.根据对象执行方法
List<Account> accounts = as.findAllAccount();
for (Account account:accounts){
System.out.println(account);
}
} @Test
public void testFindById(){
/* //1.加载配置文件
AnnotationConfigApplicationContext ca = new AnnotationConfigApplicationContext(SpringCinfiguration.class);
//2.获取服务层对象
IAccountService as = ca.getBean("accountService", IAccountService.class);*/
//3.根据对象执行方法
Account a = as.findOneById(3);
System.out.println(a);
} @Test
public void testSave(){
Account account = new Account();
account.setName("gx");
account.setMoney(1234.0f);
/*//1.加载配置文件
AnnotationConfigApplicationContext ca = new AnnotationConfigApplicationContext(SpringCinfiguration.class);
//2.获取服务层对象
IAccountService as = ca.getBean("accountService", IAccountService.class);*/
//3.根据对象执行方法
as.saveAccount(account);
} @Test
public void testUpdate(){
Account account = new Account();
account.setId(4);
account.setName("wf");
account.setMoney(1234.0f);
/* //1.加载配置文件
AnnotationConfigApplicationContext ca = new AnnotationConfigApplicationContext(SpringCinfiguration.class);
//2.获取服务层对象
IAccountService as = ca.getBean("accountService", IAccountService.class);*/
//3.根据对象执行方法
as.updateAccount(account);
}
@Test
public void testDelete(){
/* //1.加载配置文件
AnnotationConfigApplicationContext ca = new AnnotationConfigApplicationContext(SpringCinfiguration.class);
//2.获取服务层对象
IAccountService as = ca.getBean("accountService", IAccountService.class);*/
//3.根据对象执行方法
as.deleteAccount(8);
}
}

也可以在xml配置文件项目中使用此方法整合junit

SSM框架之Spring(3)IOC及依赖注入(基于注解的实现)的更多相关文章

  1. 【Spring】IoC容器 - 依赖注入

    前言 上一篇文章已经学习了[依赖查找]相关的知识,这里详细的介绍一下[依赖注入]. 依赖注入 - 分类 因为自己是基于小马哥的脉络来学习,并且很认可小马哥梳理的分类方式,下面按照小马哥思想为[依赖注入 ...

  2. Spring第七弹—依赖注入之注解方式注入及编码解析@Resource原理

        注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果. 手工装配依赖对象  手工装配依赖对象,在这种方式中又有两种编 ...

  3. SSM框架之Spring(2)IOC及依赖注入

    Spring(2)IOC及依赖注入 基于xml配置文件的实现 1.IOC (控制反转-Inversion Of Control) 控制反转(Inversion of Control,缩写为IoC),是 ...

  4. Spring学习-理解IOC和依赖注入

    最近刚买了一本介绍ssm框架的书,里面主要对Mybatis.spring.springmvc和redis做了很多的讲解,个人觉得虽然有的内容我看不懂,但是整体上还是不错的.最近正在学习中,一边学习一边 ...

  5. SSM框架之spring(1)

    spring(1) 1.spring概述 Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP( ...

  6. Ioc容器依赖注入-Spring 源码系列(2)

    Ioc容器依赖注入-Spring 源码系列(2) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostPr ...

  7. 回客科技 面试的 实现ioc 容器用到的技术,简述BeanFactory的实现原理,大搜车面试的 spring 怎么实现的依赖注入(DI)

    前言:这几天的面试,感觉自己对spring 的整个掌握还是很薄弱.所以需要继续加强. 这里说明一下spring的这几个面试题,但是实际的感觉还是不对的,这种问题我认为需要真正读了spring的源码后说 ...

  8. Spring源码之IOC容器创建、BeanDefinition加载和注册和IOC容器依赖注入

    总结 在SpringApplication#createApplicationContext()执行时创建IOC容器,默认DefaultListableBeanFactory 在AbstractApp ...

  9. 轻松学,浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI) 依赖注入和控制反转的理解,写的太好了。

    轻松学,浅析依赖倒置(DIP).控制反转(IOC)和依赖注入(DI) 2017年07月13日 22:04:39 frank909 阅读数:14269更多 所属专栏: Java 反射基础知识与实战   ...

随机推荐

  1. Asp.Net MVC Web API 中Swagger教程,使用Swagger创建Web API帮助文件

    什么是Swagger? Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法 ...

  2. Litho在美团动态化方案MTFlexbox中的实践

    1. MTFlexbox MTFlexbox是美团内部应用的非常成熟的一种跨平台动态化解决方案,它遵循了CSS3中提出的Flexbox规范来抹平多平台的差异.MTFlexbox适用于重展示.轻交互的业 ...

  3. 关于MySQL注入漏洞到获取webshell

    关于PHP网站报错性注入拿shell的方法,定位到报错在某个字段上的利用方式: 条件1: 爆出了网站的物理路径 条件2:MySQL具有into outfile权限 SQL语句为: 假如字段为2: un ...

  4. SAP Business One对象清单

    中文描述 对象号 表名 主键 英文描述 总账科目 1 OACT AcctCode G/L Accounts 业务伙伴 2 OCRD CardCode Business Partner 银行代码 3 O ...

  5. CentOS7下部署java+tomcat+mysql项目及遇到的坑

    CentOS 7 下安装部署java+tomcat+mysql 前置:CentOS7安装:https://jingyan.baidu.com/article/b7001fe1d1d8380e7382d ...

  6. 原创 Hive count 多个度量指标,带有 distinct

    Hive  count 多个度量指标,带有  distinct ,注意点!!! 比如  select  organid, ppi, count(id1) as num1, count(distinct ...

  7. UWP GridView切换数据时界面闪动

    在选择数据时,比如1-10集,和11-20集切换时,GridView需要切换对应的数据,但是会发生界面闪动. 这是默认的Item Transition导致的. 可以去掉默认的转换效果. <Gri ...

  8. FCC---CSS Flexbox: Add Flex Superpowers to the Tweet Embed

    To the right is the tweet embed that will be used as the practical example. Some of the elements wou ...

  9. 【js】canvas——Atomic-particle-motion

    原子粒动 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  10. IDEA新建servlet时出现的错误

    未注入Tomcat里lib文件下的jar 这样即可