spring的IOC是一个key,value(Map)结构
(一).常用的ioc注解
原xml方式的
<bean id="accountService" class="com.lc.service.impl.IAccountServiceImpl" scope="" init-method="" destroy-method="">
<property name="" ref="" value=""></property>
</bean>
现在的配置方式,告知扫描位置
<?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="com.lc"></context:component-scan>
</beans>
1.用于创建对象的注解 bean
@Component将当前对象存入spring容器,value用于指定bean的id
@Component(value="accountService" )
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao = new AccountDaoImpl();
@Override
public void saveAccount() {
accountDao.saveAccount();
}
}
以下三个注解的作用和属性与@component一样,用于mvc架构,可以用@component替换掉
(1)@Controller 表现层
(2)@Service 业务层
(3)@Repository 持久层
2.用于注入数据的注解 property
- @AutoWired 自动按照类型注入只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配(找不见就报错,如果找见多个相同类型,就会匹配key值一样的那个类型,都不一样就报错),就可以注入成功。
位置:方法上或者变量上
- @Qualifier: value用于指定bean的id, 不能独立使用
在按照类型注入的基础上,在按照名称注入,他在给成员注入时不能单独使用,但在给方法参数注入是可以。 - @Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
- @Lazy(true) 表示延迟初始化
- @Resource(name=“id”)
直接使用key 进行注解 - @value 用于注入基本类型和String类型的数据
指定数据的值,可以配合SpEl(spring的el表达式 ${表达式})使用
@Value("normal")
private String normal; // 注入普通字符串
@Value("#{systemProperties['os.name']}")
private String systemPropertiesName; // 注入操作系统属性
@Value("#{ T(java.lang.Math).random() * 100.0 }")
private double randomNumber; //注入表达式结果
@Value("#{beanInject.another}")
private String fromAnotherBean; // 注入其他Bean属性:注入beanInject对象的属性another,类具体定义见下面
@Value("classpath:com/hry/spring/configinject/config.txt")
private Resource resourceFile; // 注入文件资源
@Value("http://www.baidu.com")
private Resource testUrl; // 注入URL资源
3.用于改变作用范围的注解 scope
@Scope(value=“prototype”) 用于指定bean的作用范围
value属性指定作用范围:singleton/prototype/session/global-session
4.和生命周期相关的注解 init_method,destory-metory
@preDestory 用于指定销毁方法
@PostConstruct 用于指定初始化方法
(二)使用xml方式实现表单的CRUD
<?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">
<!--把对象创建交给beanFactory-->
<!--service-->
<bean id="accountService" class="com.lc.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--dao-->
<bean id="accountDao" class="com.lc.dao.impl.AccountDaoImpl">
<property name="runner" ref="runner"></property>
</bean>
<!--配置数据QueryRunner 要有set方法-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</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://localhost:3306/eesy"></property>
<property name="user" value="root"></property>
<property name="password" value="kwantler"></property>
</bean>
</beans>
private QueryRunner runner;
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
@Override
public List<Account> findAll() {
try {
return runner.query("select * from account", new BeanListHandler<Account>(Account.class));
} catch (SQLException e) {
throw new RuntimeException("列表查询");
}
}
(三)改造基于注解ioc案例,使用纯注解的方式实现
- 自建bean 改造成注解(非jar包中)
dao
service
<?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="com.lc"></context:component-scan>
<!--配置数据QueryRunner-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</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://localhost:3306/eesy"></property>
<property name="user" value="root"></property>
<property name="password" value="kwantler"></property>
</bean>
</beans>
- 完全去掉bean.xml
package config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/**
* 该类是一个配置类,他的作用和bean.xml一样
* spring中的新注解
* @Configuration 指当前类是一个配置类
* @ComponentScan 用于通过注解指定spring在创建容器时要扫描的包
* 属性:value 他和basePackages作用一样都是用来指定创建容器时要扫描的包
* 等同于在xml中配置了<context:component-scan base-package="com.lc"></context:component-scan>
*
* @Bean 将当前方法的返回值作为bean对象存入spring的容器中
* 属性:name ->用来指定bean的ID,默认是当前方法名称
* 细节:当我们用注解来配置的话,如果有参数,spring会去容器中查找是否有可用的参数
*/
@Configuration
@ComponentScan("com.lc")
public class SpringConfiguration {
/**
* @Bean 将当前方法的返回值作为bean对象存入spring的容器中
* 用于创建一个QueryRunner 对象
* @param dataSource
* @return
*/
@Bean(name="runner")
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
/**
* 创建数据源对象
* @return
*/
@Bean(name="dataSource")
public DataSource createDataSource(){
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/eesy");
ds.setUser("root");
ds.setPassword("kwantler");
return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException("数据库连接失败");
}
}
}
@Test
public void findAllTest() {
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
AccountService accountService = ac.getBean("accountService", AccountService.class);
List<Account> list = accountService.findAll();
for (Account account:list) {
System.out.println(account);
}
}
- 多配制文件,读取Properties
package config;
import org.springframework.context.annotation.*;
/**
* 该类是一个配置类,他的作用和bean.xml一样
* spring中的新注解
* @Configuration 指当前类是一个配置类
* 细节:当配置对象是AnnotationConfigApplicationContext(SpringConfiguration.class)的参数时可以不写
* @ComponentScan 用于通过注解指定spring在创建容器时要扫描的包
* 属性:value 他和basePackages作用一样都是用来指定创建容器时要扫描的包
* 等同于在xml中配置了<context:component-scan base-package="com.lc"></context:component-scan>
*
* @Bean 将当前方法的返回值作为bean对象存入spring的容器中
* 属性:name ->用来指定bean的ID,默认是当前方法名称
* 细节:当我们用注解来配置的话,如果有参数,spring会去容器中查找是否有可用的参数
* @import(JdbcConfig.class) 用于置指定其他配置类
* 属性:value用来指定其他配置字节码,有import的类就是主(父)配置类,导入的都是子配置类
* @PropertySource("classpath:jdbcConfig.properties") 用于指定properties文件的路径:classpath 表示类路径下
*/
//@Configuration
@ComponentScan("com.lc")
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}
package config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
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;
/**
* @Bean 将当前方法的返回值作为bean对象存入spring的容器中
* 用于创建一个QueryRunner 对象
* @Scope("prototype") 注明是多例
* @param dataSource
* @return
*/
@Bean(name="runner")
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
/**
* 创建数据源对象
* @return
*/
@Bean(name="dataSource")
public DataSource createDataSource(){
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException("数据库连接失败");
}
}
}
(四)spring和junit整合
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
<scope>test</scope>
</dependency>
package com.lc.test;
import com.lc.domain.Account;
import com.lc.service.AccountService;
import config.SpringConfiguration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
/**
* todo junit 单元测试
* Spring 整合junit的配置要求junite4.1.2 以上版本
* 1.导入Spring整合Junit的jar
* 2.告知spring运行器,spring和ioc创建是基于xml还是注解的,并且说明位置
* @contextConfiguration locations:指定xml文件的位置:加上classpath表示在当前类路径下
* classes: 指定注解类所在位置
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void findAllTest() {
List<Account> list = accountService.findAll();
for (Account account:list) {
System.out.println(account);
}
}
@Test
public void findByIdTest() {
Account account= accountService.findById(1);
System.out.println(account);
}
@Test
public void saveAccountTest() {
Account account = new Account();
account.setName("王麻子");
account.setMoney(12f);
accountService.saveAccount(account);
}
@Test
public void updateAccountTest() {
Account account = new Account();
account.setId(1);
account.setName("王麻");
account.setMoney(12f);
accountService.updateAccount(account);
}
@Test
public void deleteAccountTest() {
accountService.deleteAccount(4);
}
}