Spring学习之==>IoC
一、概述
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的更多相关文章
- Spring学习之Ioc控制反转(1)
开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------- ...
- Spring学习之Ioc控制反转(2)
开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------- ...
- Spring学习笔记IOC与AOP实例
Spring框架核心由两部分组成: 第一部分是反向控制(IOC),也叫依赖注入(DI); 控制反转(依赖注入)的主要内容是指:只描述程序中对象的被创建方式但不显示的创建对象.在以XML语言描述的配置文 ...
- Spring 学习笔记 IoC 基础
Spring IoC Ioc 是什么 IoC -- Inversion of Control(控制反转)什么是控制?什么是反转? 控制反转了什么? 在很早之前写项目不用 Spring 的时候,都是在 ...
- Spring学习之Ioc
Ioc原理讲解:http://www.cnblogs.com/xdp-gacl/p/4249939.html Ioc IoC是一种编程思想,由主动编程变为被动接收. 也就是说,所有的组件都是被动的(p ...
- [跟我学spring学习笔记][IoC]
IoC基础 什么是IoC Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想. ioc做什么 IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找 ...
- spring学习(一) ———— IOC讲解
spring基本就两个核心内容,IOC和AOP.把这两个学会了基本上就会用了. --WH 一.什么是IOC? IOC:控制反转,通俗点讲,将对象的创建权交给spring,我们需要new对象,则由spr ...
- spring 学习 二 IOC/DI
中文名称:控制反转 英文名称:( Inversion of Control ) 1 控制反转作用: 一般在编写java程序时,需要程序员自己创建对象的实例,例如 A a=new A();语句,就是程序 ...
- Spring学习二----------IOC及Bean容器
© 版权声明:本文为博主原创文章,转载请注明出处 接口 用于沟通的中介物的抽象化 实体把自己提供给外界的一种抽象化说明,用以由内部操作分离出外部沟通方法,使其能被修改内部而不影响外界其他实体与其交互的 ...
随机推荐
- Linux基础命令02
常用的一些命令选项 向网络发送icmp检测主机是否在线 ping 指定发送包数量 ping -c windows系统中是ping -t不间断刷包 比如ping百度,ping不同,一直卡在这里,加了-w ...
- 8.CNN应用于手写字识别
import numpy as np from keras.datasets import mnist from keras.utils import np_utils from keras.mode ...
- CNN for NLP
卷积神经网络在自然语言处理任务中的应用.参考链接:Understanding Convolutional Neural Networks for NLP(2015.11) Instead of ima ...
- URL编码以及GET和POST提交乱码解决方案 (转)
1. 什么是URL编码. URL编码是一种浏览器用来打包表单输入的格式,浏览器从表单中获取所有的name和其对应的value,将他们以name/value编码方式作为URL的一部分或者分离的发送到服 ...
- go变量和数据类型
go语言的基本数据类型 布尔类型:bool 整型:int8.byte.int16.int.uint.uintptr等 浮点类型:float32.float64 复数类型:comple ...
- pod denied问题
/Users/xxx/Library/Developer/Xcode/DerivedData/xxx-cdsvdpxrnyrnhshklcylefhdtghq/Build/Intermediates. ...
- 对Webpack 应用的研究-----------------引用
对大多数 Web 应用来说,页面性能直接影响着流量.这是一个经常为我们所忽视的事实.用户长时间的等待流失的不仅仅是跳出率.转化率,还有对产品的耐心和信赖.很多时候我们没有意识到性能问题,那是因为平常开 ...
- xcode打正式包提示缺少icon图标解决方法
报如下错,是说缺少ipad图标 解决方法 如下图创建图标库 打开新建的图标库文件夹中的contents.josn文件,把下面的代码复制到原来的图标库(可以不进行上一步建图标库,手动添加也可以) 然后把 ...
- luogu 5561 [Celeste-B]Mirror Magic 后缀数组+RMQ+multiset
思路肯定是没有问题,但是不知道为啥一直 TLE 两个点~ #include <bits/stdc++.h> #define N 2000006 #define setIO(s) freop ...
- BZOJ 1951: [Sdoi2010]古代猪文 ExCRT+欧拉定理+Lucas
欧拉定理不要忘记!! #include <bits/stdc++.h> #define N 100000 #define ll long long #define ull unsigned ...