一、概述

Spring的三大核心思想:IoC(控制反转),DI(依赖注入),AOP(面向切面编程)。本问讲着重介绍一下控制反转。

何谓控制反转:Spring 通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

通俗的讲,控制权由代码中转到了外部容器,控制权的转移,就是所谓反转。也就是说,正常我们都是 new 一个新对象,才可以调用对象。有了控制反转就不需要了,交给容器来管理,我们只需要通过一些配置来完成把实体类交给容器这么个过程。这样可以减少代码量,简化开发的复杂度和耦合度。

二、面向接口编程

在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

面向接口编程,具体到某一个接口,对于调用者来说,我们不关心该接口是由哪个实现类来实现的,也不关心具体是怎么实现的,你只需把该接口提供给调用者就可以了。

三、编码实现IoC

下面,我们使用IoC思想来实现一个简单的面向接口编程。

首先定义两个接口 IAccountService 和 IOrderService,如下:

public interface IAccountService {

  int insertAccount(String msg);

}

IAccountService 接口

public interface IOrderService {

  void insert(String msg);

}

IOrderService 接口

然后,定义这两个接口的实现类

public class AccountBigServiceImpl implements IAccountService {

  @Override
public int insertAccount(String msg) { System.out.println("===== AccountBigServiceImpl ====" + msg); return 0;
}
}

AccountBigServiceImpl

public class AccountSamllServiceImpl implements IAccountService {

  @Override
public int insertAccount(String msg) { System.out.println("smallService"); return 0;
}
}

AccountSamllServiceImpl

public class OrderServiceImpl implements IOrderService {

  @Override
public void insert(String msg) { System.out.println("===== OrderServiceImpl ====" + msg);
}
}

OrderServiceImpl

正常我们使用下面这段代码来调用这两个接口

public class Controller {
public static void main(String[] args) {
IAccountService accountService = new AccountBigServiceImpl();
accountService.insertAccount("Hello!!"); IOrderService orderService = new OrderServiceImpl();
orderService.insert("World!!");
}
}

我们在 Controller 这个类中直接 new 了 IAccountService 和 IOrderService 这两个接口的子类:AccountBigServiceImpl 和 OrderServiceImpl。这样就违背上面提到的面向接口编程的思想,我既要处理 Controller 这个类中的业务逻辑,还要关心 IAccountService 和 IOrderService 这两个接口具体的实现类是谁,上面是使用 AccountBigServiceImpl 这个类来实现接口 IAccountService,如果我要使用 AccountSamllServiceImpl这个实现类来实现这个接口,那我还得修改 Controller 中的代码,显然这样做的维护成本就太高了,而且也很容易出错,那么,我们可以想其他的办法。

首先,我们使用一个配置文件来定义这两个接口指向的实现类

IAccountService=com.jack.course.spring.factory.impl.AccountBigServiceImpl
IOrderService=com.jack.course.spring.factory.impl.OrderServiceImpl

conf.properties

然后,我们再定义一个工厂类

public class ServiceFactory {

  private static final String CONF_FILE_NAME = "factory/conf.properties";

  private static Properties prop;

  private static Map<String, Object> beanContainer;

  /**
* 静态代码块,程序执行时只会被加载一次
*/
static { try {
beanContainer = Maps.newHashMap();
//1.从配置文件中找出关系
prop = new Properties();
prop.load(ServiceFactory.class.getClassLoader().getResourceAsStream(CONF_FILE_NAME));
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
} public static <T> T getService(Class<T> clazz){ if (beanContainer.containsKey(clazz.getSimpleName())){
return (T) beanContainer.get(clazz.getSimpleName());
} try {
//2.根据关系,将具体的实现类返回
Object obj = instanceObj(clazz);
beanContainer.put(clazz.getSimpleName(),obj);
return (T) obj;
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
} private static <T> Object instanceObj(Class<T> clazz) throws Exception {
String className = prop.getProperty(clazz.getSimpleName());
Class<?> instance = Class.forName(className);
return instance.newInstance();
}
}

注意:以上代码做了两处优化。第一,把读取配置文件的操作单独抽出来放入静态代码块,只会执行一次不会重复读取。第二,定义了一个 Map 作为 bean容器存放实例化后的对象,如果容器中已经存在实例化后的对象就可以直接返回,不用在重现通过 instanceObj() 方法来实例化对象了,通过这两处优化,能够大大提高性能。

这个工厂类实现的功能是:通过读取配置文件 conf.properties 得到接口的具体实现类,然后通过反射来生成一个对象传给 Controller,这样 Controller 类当中就可以不关心接口的实现类是谁,怎么实现也不用关心。

那我们 Controller 中就可以这么实现

public class Controller {
public static void main(String[] args) { IAccountService accountService = ServiceFactory.getService(IAccountService.class);
accountService.insertAccount("Hello!"); IOrderService orderService1 = ServiceFactory.getService(IOrderService.class);
IOrderService orderService2 = ServiceFactory.getService(IOrderService.class);
orderService1.insert("One");
orderService2.insert("Two");
}
}

这样,我们如果想修改实现类的话,只需要修改配置文件就行了,不用修改代码。

运行结果如下:

以上,我们就通过 IoC 的思想实现了面向接口编程。但是,我们这样的实现就完全没有问题吗?

我们稍微修改一下 AccountBigServiceImpl 实现类,增加一个有参数的构造方法来覆盖默认的构造方法

public class AccountBigServiceImpl implements IAccountService {

  private AccountBigServiceImpl(String msg) {
System.out.println(msg);
} @Override
public int insertAccount(String msg) { System.out.println("===== AccountBigServiceImpl ====" + msg); return 0;
}
}

然后再执行 Controller,就会报错了。原因是因为我们使用 newInstance 实例化对象时使用的是默认的无参构造方法。

那么,我们通过修改工厂类,也可以实现该功能。但是,可能慢慢还会发现有其他问题,那么我们是不是要全部自己来实现呢,我们可以直接来使用 Spring 框架即可。Spring 框架把我们能想到的和想不到的功能都给实现了,我们只需直接使用就可以了。

四、使用XML文件配置IoC

我们基于 MVC 三层架构来做一个简单的实现,分为:表现层(Controller)、业务逻辑层(Service)和持久层(Dao)。

定义两个接口

public interface IocxService {

  String foo(String msg);

}

IocxService 接口

public interface IocxDao {

  String iocxFoo(String msg);

}

IocxDao 接口

再定义三个类,IocxController、IocxServiceImpl 和 IocxDaoImpl

public class IocxController {

  private IocxService iocxService;

  public IocxController() {
System.out.println("***** IocxController init ******");
} public String iocxFoo(String msg){ return iocxService.foo(msg);
} public void setIocxService(IocxService iocxService){ this.iocxService = iocxService; }
}

IocxController

public class IocxServiceImpl implements IocxService {

  private IocxDao iocxDao;

  private Set<String> infos;

  private List<IocxAccount> accounts;

  private Map<String, String> mapData;

  @Override
public String foo(String msg) { System.out.println("IocxServiceImpl = " + msg); System.out.println("infos = " + infos); return iocxDao.iocxFoo("account");
} public void setIocxDao(IocxDao iocxDao) {
this.iocxDao = iocxDao;
} public void setInfos(Set<String> infos) {
this.infos = infos;
} public void setAccounts(List<IocxAccount> accounts) {
this.accounts = accounts;
} public void setMapData(Map<String, String> mapData) {
this.mapData = mapData;
}
}

IocxServiceImpl

public class IocxDaoImpl implements IocxDao {

  private String info;
private Integer rows; public IocxDaoImpl(String info) {
this.info = info;
System.out.println("单参数构造方法");
} public IocxDaoImpl(String info, Integer rows) {
this.info = info;
this.rows = rows;
System.out.println("俩参数构造方法");
} @Override
public String iocxFoo(String msg) {
return "IocxDaoImpl response";
}
}

IocxDaoImpl

IocxController 为 Controller 层,定义一个类型为 IocxService(Service层) 的依赖属性,同时也定义了这个依赖属性的 set 方法。

IocxServiceImpl 为 Service 层,定义了一个类型为 IocxDao(Dao层) 的依赖属性,同时定义了另外三个 Set、List 和 Map 属性,并为这四个属性定义 set 方法

IocxDaoImpl 为 Dao 层,定义了两个不同参数的构造方法以及实现了 IocxDao 接口的 iocxFoo 方法。

就这样,Controller 层依赖于 Service 层,Service 层依赖于 Dao 层。

再来看一下 XML 配置文件 beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 默认实现单例: scope="singleton" -->
<!-- 要实现多例: scope="prototype" -->
<bean id="controller" class="com.jack.course.spring.iocx.controller.IocxController"
scope="prototype">
<!-- DI,依赖注入,基于属性往对应的对象中注入数据 -->
<property name="iocxService" ref="service"/>
</bean> <bean id="service" class="com.jack.course.spring.iocx.service.impl.IocxServiceImpl">
<property name="iocxDao" ref="dao"/>
<!-- Set注入 -->
<property name="infos">
<set>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</set>
</property>
<!-- List注入 -->
<property name="accounts">
<list>
<ref bean="abc1"/>
<ref bean="abc2"/>
<ref bean="abc3"/>
</list>
</property>
<!-- Map注入 -->
<property name="mapData">
<map>
<entry key="k1" value="v1"/>
<entry key="k1" value="v1"/>
</map>
</property>
</bean> <bean id="abc1" class="com.jack.course.spring.iocx.pojo.IocxAccount">
<property name="name" value="hahah-haha"/>
</bean> <bean id="abc2" class="com.jack.course.spring.iocx.pojo.IocxAccount">
<property name="name" value="hahah-haha"/>
</bean> <bean id="abc3" class="com.jack.course.spring.iocx.pojo.IocxAccount">
<property name="name" value="hahah-haha"/>
</bean> <bean id="dao" class="com.jack.course.spring.iocx.dao.impl.IocxDaoImpl">
<constructor-arg value="test" index="0"/>
<constructor-arg value="1024" index="1"/>
</bean> <!-- 懒加载:用到时才加载,不用时不加载 -->
<bean id="orderTestLazy" class="com.jack.course.spring.iocx.pojo.OrderTestLazy"
lazy-init="true"/> </beans>

beans.xml

从 XML 配置文件中可以看到,我们将每一个类都通过 id 和 class 对应的关系放入到了每个 bean 标签当中,id需要是唯一的,这就有点像上面我们自己实现 IoC 的时候定义的properties配置文件,Spring 一样是通过反射机制去加载类和生成对象。同时,我们看到配置文件中是通过 property 标签,基于属性的名字往对应的对象中去注入数据,这就是所谓的 DI(依赖注入),不过这里有个前提,这个属性必须在对应的类中定义且实现了它的 set 方法。另外,像非自定义的属性类型 Set、List、Map 的属性,XML文件中同样描述了如何注入。下面是测试程序:

public class App {

  @Test
public void testNormal() {
ApplicationContext context = new ClassPathXmlApplicationContext("iocx/beans.xml");
IocxController controller = context.getBean("controller", IocxController.class);
String response = controller.iocxFoo("hello");
System.out.println("response:::" + response);
} /**
* 测试单例/多例模式
* 默认: scope="singleton"
* 要实现多例: scope="prototype"
*/
@Test
public void testScope() {
ApplicationContext context = new ClassPathXmlApplicationContext("iocx/beans.xml"); for (int i = 0; i < 5; i++) {
IocxController controller = context.getBean("controller", IocxController.class);
System.out.println("controller = " + controller);
}
} @Test
public void testFactory() {
ApplicationContext context = new ClassPathXmlApplicationContext("iocx/beans.xml"); Object obj = context.getBean("beanFactory"); // com.jack.course.spring.iocx.service.impl.IocxServiceImpl@6b53e23f
System.out.println("obj = " + obj);
} /**
* 测试懒加载
*
* 默认是非懒加载
*
* 需要配置懒加载时,设置属性 lazy-init="true"
*/
@Test
public void testLazyInit() {
ApplicationContext context = new ClassPathXmlApplicationContext("iocx/beans.xml"); // Object controller = context.getBean("controller"); Object orderTestLazy = context.getBean("orderTestLazy"); // System.out.println("controller = " + controller); System.out.println("orderTestLazy = " + orderTestLazy);
}
}

App 测试类

步骤是先读取配置文件,再生成实例化对象,最后再调用方法。使用配置文件的方法看上去比较麻烦,现在已经很少有人使用这种方式。

五、使用注解+XML文件配置IoC

同样,还说先定义两个接口

public interface IocaService {

  String foo(String msg);

}

IocaService 接口

public interface IocaDao {

  String foo(String msg);

}

IocaDao 接口

接着是三个类,IocaController、IocaServiceImpl 和 IocaDaoImpl

@Controller // 相当于是<bean id=xxx class=xxx>
public class IocaController { @Autowired // 相当于是 <propertity name=iocaService ref="">
private IocaService iocaService;
public String foo(String msg) {
return iocaService.foo(msg);
} @Autowired
private Gson gson;
public String format(Object object) {
return gson.toJson(object);
}
}

IocaController

@Service
public class IocaServiceImpl implements IocaService { @Autowired
private IocaDao iocaDao; @Override
public String foo(String msg) {
return iocaDao.foo(msg);
}
}

IocaServiceImpl

@Repository
public class IocaDaoImpl implements IocaDao { @Override
public String foo(String msg) { System.out.println("msg = " + msg); return "dao response!!!";
}
}

IocaDaoImpl

我们注意到:Controller、Service、Dao层分别使用 @Controller、@Service 和 @Repository 注解,关联属性使用 @Autowired 注解注入数据。

再来看一下 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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 创建容器时指定扫描包的路径 -->
<context:component-scan base-package="com.jack.course.spring.ioca"/> <!-- 因为不能给非自定义类加注解,所以需要在配置文件中注明 -->
<bean id="gson" class="com.google.gson.Gson"/>
</beans>

配置文件中主要有两个内容,一个是指明注解扫描的包的路径,二是 IocaController 类中定义了 Gson 类型的属性,该类属于第三方 Jar包,没有办法添加注解,所以需要在配置文件中注明。下面是测试程序:

public class App {

  @Test
public void testNormal() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ioca/beans.xml"); IocaController controller = applicationContext.getBean(IocaController.class); String resp = controller.foo("hello"); System.out.println("resp = " + resp);
} @Test
public void testFormat() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ioca/beans.xml"); IocaController controller = applicationContext.getBean(IocaController.class); Map<String, String> mapData = Maps.newHashMap();
mapData.put("abc", "xyz");
mapData.put("name", "jim"); String resp = controller.format(mapData);
System.out.println("resp = " + resp);
}
}

App 测试类

步骤同样是先读取配置文件,再生成实例化对象,最后再调用方法。注解加配置文件的方式看上去比较简介,但是如果引入的第三方 Jar包比较多,在配置文件中就需要添加很多内容,所以这种方式也不建议使用。

六、使用全注解配置IoC

使用全注解的方式我们就不需要 XML 配置文件了,只需要新增一个配置类。同时,如果有一些数据库的配置文件需要加载的话,也可以在配置文件中进行配置

/**
* 注解配置文件
* @author Luolei
*/
// 相当于 beans.xml,标注这是一个配置类
@Configuration // <context:component-scan base-package="com.jack.course.spring.ioca"/>
@ComponentScan(basePackages = "com.jack.course.spring.ioca") // 相当于我们自己实例化了一个Properties对象, 并将相关数据读进来
@PropertySource("ioca/db.properties")
public class IocaConfiguration { // 相当于 <bean id="gson" class="com.google.gson.Gson"/>
@Bean
public Gson createGson(){
return new Gson();
} @Value("${driver}")
private String driver;
@Value("${url}")
private String url;
@Value("${usname}")
private String username;
@Value("${passwd}")
private String passwd;
@Bean
public DataSource createDataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(passwd); System.out.println("config datasources: " + driver + "*" + url
+ "*" + username + "*" + passwd); return dataSource;
}
}

测试程序如下:

/**
* 读取配置类IocaConfiguration
*/
public class App { @Test
public void testFormat() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(IocaConfiguration.class); IocaController controller = applicationContext.getBean(IocaController.class); Map<String, String> mapData = Maps.newHashMap();
mapData.put("abc", "123");
mapData.put("name", "456"); String resp = controller.format(mapData);
System.out.println("resp = " + resp);
} @Test
public void testDataSource() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(IocaConfiguration.class); IocaController controller = applicationContext.getBean(IocaController.class); controller.callDataSource();
}
}

App 测试类

这里读取的就不是 XML 配置文件,而是上面那个配置类。

常用注解说明:

  • @Component

    • 用于把当前类对象存入spring容器中;
    • 属性 value:用于指定bean的id。当我们不写时,它的默认值是当前类名首字母改小写;
  • @Controller
    • 一般用于表现层;
  • @Service
    • 一般用于业务层;
  • @Repository
    • 一般用于持久层;

以上三个注解他们的作用和Conmponant一样。

它们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰用于注入数据的。

它们的作用就和在 xml 配置文件中的 bean 标签中写一个<property>标签的作用是一样的。

  • @Autowired

    • 自动按照类型注入,只要容器中有唯一的一个 bean 对象类型和要注入的变量类型匹配,就可以注入成功;
    • 如果 IoC 容器中没有任何 bean 的类型和要注入的变量类型匹配,则报错;
    • 如果 IoC 容器中有多个类型匹配时,先按照数据类型在 IoC中 查找,再以变量名称为 IoC 中 id 查找 bean 对象注入;
    • 书写位置可以是变量上,也可以是方法上;
    • 和使用 XML 配置文件不一样的是:在使用注解注入时,set方法就不是必须的了;
  • @Qualifier
    • 在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以;
    • 属性value:用于指定注入bean的 id;
  • @Resource
    • 直接按照bean的id注入,可以独立使用;
    • 属性name:用于指定bean的 id;

以上三种注解只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。另外,集合类型的注入只能用 XML 文件来实现。

  • @Value

    • 用于注入基本类型和String类型的数据;
    • 属性value:用于指定数据的值,它可以使用 spring 中 SpEL表达式;
    • SpEL 表达式的写法:${表达式};
  • @Scope
    • bean的作用范围;
    • 属性value:两个值 singleton 和 prototype;
      • singleton单例模式:全局有且仅有一个实例;
      • prototype原型模式:每次获取Bean的时候会有一个新的实例;

新增注解:

  • @Configuration

    • 指定当前类是一个配置类,它的作用和bean.xml一样;
    • 当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写;
    • 配置类中可以不写,因为获取容器时通过ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);扫描主配置类。其余配置类需要写。并在主配置类中@ComponentScan({"com.test"})添加扫描的类,建议最好还是写,免得麻烦;
  • @ComponentScan
    • 用于通过注解指定spring在创建容器时要扫描的包;
    • 属性value:它和basePackages的作用一样,都适用于指定创建容器时要扫描的包;
    • 我们使用此注解就等同于在xml中配置了:<context:component-scan base-package="com.jack.course.spring.ioca"/>;
    • 默认就会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中。当然,这个的前提就是你需要在所扫描包下的类上引入注解。
  • @Bean
    • 把当前方法的返回值作为bean对象存入spring的ioc容器中;
    • 属性name:用于指定bean的id。默认值是当前方法的名称;
    • 当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象;
    • 查找的方式和Autowired注解的作用是一样的。先根据数据类型查找,再根据id查找,均在ioc容器中查找;
  • @PropertySource
    • 用于指定properties文件的位置;
    • 属性value:指定文件的名称和路径;
  • @Import
    • 导入其他的配置类.指定配置类的.class;
    • 属性value:用于指定配置类的字节码;
    • 当我们使用Import的注解之后,有Import注解的类就是父配置类即主配置类,而导入的都是子配置类;

七、Spring 整合 Junit

@Controller // 相当于是<bean id=xxx class=xxx>
public class IocaController { @Autowired // 相当于是 <propertity name=iocaService ref="">
private IocaService iocaService;
public String foo(String msg) {
return iocaService.foo(msg);
} @Autowired
private Gson gson;
public String format(Object object) {
return gson.toJson(object);
} @Autowired
private DataSource dataSource;
public void callDataSource(){
System.out.println(dataSource);
}
}

IocaController

// 相当于 beans.xml,标注这是一个配置类
@Configuration // <context:component-scan base-package="com.jack.course.spring.ioca"/>
@ComponentScan(basePackages = "com.jack.course.spring.ioca")
// @ComponentScan(value = "com.jack.course.spring.ioca") // 相当于我们自己实例化了一个Properties对象, 并将相关数据读进来
@PropertySource("ioca/db.properties")
public class IocaConfiguration { // 相当于 <bean id="gson" class="com.google.gson.Gson"/>
@Bean(name = "gson")
public Gson createGson(){
return new Gson();
} @Value("${driver}")
private String driver;
@Value("${url}")
private String url;
@Value("${usname}")
private String username;
@Value("${passwd}")
private String passwd; /**
* 创建数据源对象
* @return DataSource
*/
@Scope("prototype")
@Bean(name = "dataSource")
public DataSource createDataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(passwd); System.out.println("config datasources: " + driver + "*" + url
+ "*" + username + "*" + passwd); return dataSource;
}
}

IocaConfiguration

使用Spring 做单测

@RunWith(SpringJUnit4ClassRunner.class)
/**
* 加载配置类IocaConfiguration
* 相当于: ApplicationContext context = new AnnotationConfigApplicationContext(IocaConfiguration.class)
*
* 也可以使用xml配置文件的形式
* 相当于:ApplicationContext applicationContext = new ClassPathXmlApplicationContext("iocx/beans.xml");
*/
// @ContextConfiguration(locations = {"classpath:iocx/beans.xml"})
@ContextConfiguration(classes = IocaConfiguration.class)
public class App2 { @Autowired
private IocaController controller; @Test
public void testNormal() {
String resp = controller.foo("hello");
System.out.println("resp = " + resp);
} @Test
public void testFormat() {
Map<String, String> mapData = Maps.newHashMap();
mapData.put("abc", "xyz");
mapData.put("name", "jim"); String resp = controller.format(mapData);
System.out.println("resp = " + resp);
}
}

@RunWith(SpringJUnit4ClassRunner.class)

  • 就是一个运行器,测试时使用,里面的参数需要传入 .class类对象;
  • @RunWith(SpringJUnit4ClassRunner.class) 表示让测试运行于 Spring 环境;

@ContextConfiguration(classes = IocaConfiguration.class)

  • 用于Spring整合JUnit4测试时,使用注解引入配置类或xml配置文件;
  • 属性 locations:引入xml 配置文件;
  • 属性classes:引入配置类;

八、Spring 整合 JDBC

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
https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"/>
</bean> <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.182.128:3306/cakes"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean> </beans>

首先将 jdbcTemplate 和 datasource 加入bean 容器

测试程序

/**
* 读取jdbc/beans.xml文件中的配置
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:jdbc/beans.xml")
public class App { @Autowired
private JdbcTemplate template; @Test
public void testSpringJdbcTemplate(){
template.execute("insert into user(name,passwd) values('jack','123455')");
}
}

注解版

数据库连接配置

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://192.168.182.128:3306/cakes
usname=root
passwd=123456

db.properties

配置类

@Configuration
@ComponentScan(basePackages="com.jack.course.spring.jdbc")
@PropertySource("jdbc/db.properties")
public class JdbcConfiguration { @Value("${driver}")
private String driver;
@Value("${url}")
private String url;
@Value("${usname}")
private String userName;
@Value("${passwd}")
private String passwd; /**
* 用于创建一个JdbcTemplate对象
*/
@Bean
public JdbcTemplate createTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
} /**
* 创建数据源对象
*/
@Bean
public DataSource createDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(userName);
dataSource.setPassword(passwd); return dataSource;
}
}

JdbcConfiguration

测试程序

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = JdbcConfiguration.class)
public class App2 { @Autowired
private JdbcTemplate jdbcTemplate; @Test
public void testSpringJdbcTemplate(){
jdbcTemplate.execute("insert into user(name,passwd) values('木木','123459')");
}
}

Spring学习之==>IoC的更多相关文章

  1. Spring学习之Ioc控制反转(1)

    开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------- ...

  2. Spring学习之Ioc控制反转(2)

    开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------- ...

  3. Spring学习笔记IOC与AOP实例

    Spring框架核心由两部分组成: 第一部分是反向控制(IOC),也叫依赖注入(DI); 控制反转(依赖注入)的主要内容是指:只描述程序中对象的被创建方式但不显示的创建对象.在以XML语言描述的配置文 ...

  4. Spring 学习笔记 IoC 基础

    Spring IoC Ioc 是什么 IoC -- Inversion of Control(控制反转)什么是控制?什么是反转? 控制反转了什么? 在很早之前写项目不用 Spring 的时候,都是在 ...

  5. Spring学习之Ioc

    Ioc原理讲解:http://www.cnblogs.com/xdp-gacl/p/4249939.html Ioc IoC是一种编程思想,由主动编程变为被动接收. 也就是说,所有的组件都是被动的(p ...

  6. [跟我学spring学习笔记][IoC]

    IoC基础 什么是IoC Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想. ioc做什么 IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找 ...

  7. spring学习(一) ———— IOC讲解

    spring基本就两个核心内容,IOC和AOP.把这两个学会了基本上就会用了. --WH 一.什么是IOC? IOC:控制反转,通俗点讲,将对象的创建权交给spring,我们需要new对象,则由spr ...

  8. spring 学习 二 IOC/DI

    中文名称:控制反转 英文名称:( Inversion of Control ) 1 控制反转作用: 一般在编写java程序时,需要程序员自己创建对象的实例,例如 A a=new A();语句,就是程序 ...

  9. Spring学习二----------IOC及Bean容器

    © 版权声明:本文为博主原创文章,转载请注明出处 接口 用于沟通的中介物的抽象化 实体把自己提供给外界的一种抽象化说明,用以由内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的 ...

随机推荐

  1. Linux基础命令02

    常用的一些命令选项 向网络发送icmp检测主机是否在线 ping 指定发送包数量 ping -c windows系统中是ping -t不间断刷包 比如ping百度,ping不同,一直卡在这里,加了-w ...

  2. 8.CNN应用于手写字识别

    import numpy as np from keras.datasets import mnist from keras.utils import np_utils from keras.mode ...

  3. CNN for NLP

    卷积神经网络在自然语言处理任务中的应用.参考链接:Understanding Convolutional Neural Networks for NLP(2015.11) Instead of ima ...

  4. URL编码以及GET和POST提交乱码解决方案 (转)

    1.  什么是URL编码. URL编码是一种浏览器用来打包表单输入的格式,浏览器从表单中获取所有的name和其对应的value,将他们以name/value编码方式作为URL的一部分或者分离的发送到服 ...

  5. go变量和数据类型

          go语言的基本数据类型   布尔类型:bool 整型:int8.byte.int16.int.uint.uintptr等 浮点类型:float32.float64  复数类型:comple ...

  6. pod denied问题

    /Users/xxx/Library/Developer/Xcode/DerivedData/xxx-cdsvdpxrnyrnhshklcylefhdtghq/Build/Intermediates. ...

  7. 对Webpack 应用的研究-----------------引用

    对大多数 Web 应用来说,页面性能直接影响着流量.这是一个经常为我们所忽视的事实.用户长时间的等待流失的不仅仅是跳出率.转化率,还有对产品的耐心和信赖.很多时候我们没有意识到性能问题,那是因为平常开 ...

  8. xcode打正式包提示缺少icon图标解决方法

    报如下错,是说缺少ipad图标 解决方法 如下图创建图标库 打开新建的图标库文件夹中的contents.josn文件,把下面的代码复制到原来的图标库(可以不进行上一步建图标库,手动添加也可以) 然后把 ...

  9. luogu 5561 [Celeste-B]Mirror Magic 后缀数组+RMQ+multiset

    思路肯定是没有问题,但是不知道为啥一直 TLE 两个点~ #include <bits/stdc++.h> #define N 2000006 #define setIO(s) freop ...

  10. BZOJ 1951: [Sdoi2010]古代猪文 ExCRT+欧拉定理+Lucas

    欧拉定理不要忘记!! #include <bits/stdc++.h> #define N 100000 #define ll long long #define ull unsigned ...