Spring入门的简单知识点总结第二弹,分享给大家。希望对大家有帮助,后续更新!
Spring入门的简单知识点总结第二弹,分享给大家。希望对大家有帮助,后续更新!
spring-2
具体知识点
- 能够编写spring的IOC的注解代码
- 能够编写spring使用注解实现组件扫描
- 能够说出spring的IOC的相关注解的含义
- 够实现spring基于XML的IoC案例
- 能够实现spring基于注解的IoC案例
- 能够实现spring框架整合JUnit
一,使用 spring的IoC的实现账户的CRUD
1.环境搭建
1.1创建Maven工程,导入坐标
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.14</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
1.2创建数据库和编写实体类
- 数据库
create table account(
id int primary key auto_increment,
name varchar(40),
money double
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('zs',1000);
insert into account(name,money) values('ls',1000);
insert into account(name,money) values('ww',1000);
- 实体
public class Account implements Serializable{
private Integer id;
private String name;
private Double money;
}
1.3编写持久层代码
- AccountDao.java
public interface AccountDao {
void save(Account account) throws SQLException;
void update(Account account) throws SQLException;
void delete(Integer id) throws SQLException;
Account findById(Integer id) throws SQLException;
List<Account> findAll() throws SQLException;
}
- AccountDaoImpl.java(里面的DBUtils工具也可以使用JdbcTemplate)
public class AccountDaoImpl implements AccountDao {
private QueryRunner queryRunner;
public void setQueryRunner(QueryRunner queryRunner) {
this.queryRunner = queryRunner;
}
@Override
public void save(Account account) throws SQLException {
//3. 执行sql语句
queryRunner.update("insert into values(?,?,?)",null,account.getName(),account.getMoney());
}
@Override
public void update(Account account) throws SQLException {
//3. 执行sql语句
queryRunner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
@Override
public void delete(Integer id) throws SQLException {
//3. 执行sql语句
queryRunner.update("delete from account where id=?",id);
}
@Override
public Account findById(Integer id) throws SQLException {
//3. 执行sql语句
return queryRunner.query("select * from account where id=?",new BeanHandler<Account>(Account.class),id);
}
@Override
public List<Account> findAll() throws SQLException {
//3. 执行sql语句
return queryRunner.query("select * from account ",new BeanListHandler<Account>(Account.class));
}
}
1.4编写业务层代码
- AccountService.java
public interface AccountService {
void save(Account account) throws Exception;
void update(Account account) throws Exception;
void delete(Integer id) throws Exception;
Account findById(Integer id) throws Exception;
List<Account> findAll() throws Exception;
}
- AccountServiceImpl.java
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void save(Account account) throws Exception {
accountDao.save(account);
}
@Override
public void update(Account account) throws Exception {
accountDao.update(account);
}
@Override
public void delete(Integer id) throws Exception {
accountDao.delete(id);
}
@Override
public Account findById(Integer id) throws Exception {
return accountDao.findById(id);
}
@Override
public List<Account> findAll() throws Exception {
return accountDao.findAll();
}
}
2.配置步骤
- 创建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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--注册AccountService-->
<bean id="accountService" class="com.lovejava.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--注册accountDao-->
<bean id="accountDao" class="com.lovejava.dao.impl.AccountDaoImpl">
<property name="queryRunner" ref="queryRunner"/>
</bean>
<!--注册queryRunner-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!--注册数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf8"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>
3.测试案例
public class DbTest {
@Test
public void fun01() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
List<Account> list = accountService.findAll();
System.out.println(list);
}
}
二,Spring的IOC注解开发
学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现的功能都是一样的,都是要降低程序间的耦合。只是配置的形式不一样。
1.注解开发入门
1.1创建Maven工程,添加依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
1.2使用@Component注解配置管理的资源
- eg: 需要给AccountServiceImpl
@Component("accountService")
public class AccountServiceImpl implements AccountService {} // 等同于 在xml里面,<bean id="accountService" class="具体的类">
1.3引入context的命名空间
- bean.xml中需要引入context的命名空间,可在xsd-configuration.html中找到
<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">
</beans>
1.4 配置扫描
在bean标签内部,使用context:component-scan ,让spring扫描该基础包下的所有子包注解
<context:component-scan base-package="com.lovejava"></context:component-scan>
2.注解开发进阶
2.1用于创建对象的
相对于相当于: <bean id="" class="">
[email protected]
作用:
把资源让 spring 来管理。相当于在 xml 中配置一个 bean。
属性:
value:指定 bean 的 id。如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。
[email protected] @Service @Repository
web里面的三层结构 中的所有类,在spring里面都称之为 Component (组件) , 但是它也提供了更详细的注解来针对不同的层级声明 。
三个衍生注解如下:
@Controller :修饰WEB层类 --->action | SpringMVC
@Service :修饰业务层类 --->service
@Repository :修饰DAO层类 --->dao
在需要spring创建对象的类上面使用注解 @Component(“us”) 即可.Spring看类上是否有该注解,如果有该注解,生成这个类的实例。如果不指定value值, 那么默认的id值就是类名的名字, 第一个字母小写.
四种注解
@Component 主要用于普通类
@Controller主要用于dao持久层
@Service主要应用在service有业务层
@Repository 主要应用在web表现层
原理相同,混用不会出现异常或者错误。
2.2用于改变作用范围的@scope
@scope
singleton: 单例(默认)
prototype:多例
@Scope注解用来描述类的作用范围的,默认值singleton。如同xml中bean标签的属性scope <bean scope=""/>
.如果配置成多例的使用prototype。
@Scope("prototype")
@Component("accountService")
public class AccountServiceImpl implements AccountService {}
2.3和生命周期相关的【了解】
-
初始化和销毁回调方法对应的注解
@PostConstrut:如同xml中bean标签的属性init-method
<bean init-method=""/>
,用来设置spring框架初始化此类实例时调用的初始化方法,标注在此类的初始化方法上 @PreDestroy:如同xml中bean标签的属性init-method
<bean destroy-method=""/>
,用来设置spring框架销毁此类实例时调用的销毁方法,标注在此类的销毁方法上注意:这两个注解都是配在方法上的
3.使用注解注入属性
[email protected]
-
作用:
注入基本数据类型和 String 类型数据的
-
属性:
value:用于指定值 , 可以通过表达式动态获得内容再赋值
-
实例:
@Value("帕奇")
private String name;
[email protected]
-
作用:
自动按照类型注入。当使用注解注入属性时, set 方法可以省略。它只能注入其他 bean 类型。
如果只有一个实现类, 可以自动注入成功
如果有两个或者两个以上的实现类, 找到变量名一致的id对象给注入进去(已经添加了Qualifier注解的会在根据name去注入,依然找不到,报错), 如果找不到,就报错
-
实例:
@Component("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
//当有多个AccountDao实现类时候, @Autowired会在在Spring容器里面找id为accountDao的对象注入,找不到就报错
private AccountDao accountDao;
@Override
public void save() {
System.out.println("AccountServiceImpl---save()");
accountDao.save();
}
}
[email protected]
-
作用
在自动按照类型注入(@Autowired)的基础之上,再按照Bean的id注入。
它在给字段注入时不能独立使用,必须和@Autowire一起使用;
但是给方法参数注入时,可以独立使用。
-
属性
value:指定bean的id。
-
实例
@Component("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
@Qualifier(value = "accountDao02")
private AccountDao accountDao;
@Override
public void save() {
System.out.println("AccountServiceImpl---save()");
accountDao.save();
}
}
[email protected]
如果上面一个接口有多种实现,那么现在需要指定找具体的某一个实现,那么可以使用@Resource
@Component("accountService")
public class AccountServiceImpl implements AccountService {
@Resource(name = "accountDao02")
private AccountDao accountDao;
@Override
public void save() {
System.out.println("AccountServiceImpl---save()");
accountDao.save();
}
}
4.混合开发
4.1注解和XML比较
- xml方式
- 优点: 统一管理的, 方便维护
- 缺点: 相对注解而言, 麻烦一点
- 注解方式
- 优点: 开发方便
- 缺点: 维护麻烦一点
4.2混合开发特点
使用xml(注册bean)来管理bean,
使用注解来注入属性
4.3混合开发环境搭建
-
创建spring配置文件,编写头信息配置
<?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 "> </beans>
-
配置扫描
<context:component-scan base-package="com.lovejava" />
-
在xml配置中添加Bean的管理
-
在被管理bean对应的类中,为依赖添加注解配置
三,案例:使用注解IOC改造开头的案例
1.改造步骤
- 使用注解配置持久层
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private QueryRunner queryRunner;
...
}
- 使用注解配置业务层
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
...
}
- 修改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">
<context:component-scan base-package="com.lovejava"></context:component-scan>
<!--注册queryRunner-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"/>
</bean>
<!--注册数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf8"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>
2.spring的纯注解配置
2.1概述
基于注解的IoC配置已经完成,但是大家都发现了一个问题:我们依然离不开spring的xml配置文件,那么能不能不写这个bean.xml,所有配置都用注解来实现呢?
需要注意的是,我们选择哪种配置的原则是简化开发和配置方便,而非追求某种技术
做什么功能是产品决定的
用什么技术是项目经理决定的
了解、学习纯注解(xml都不要了)目的
如果你以后要学习SpringBoot,这个就是一种准备, 方便阅读SpringBoot源码
- 上面案例:待改造的问题
<?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">
<!--1. 没有bean.xml,我们把这些配置写在哪里? 解决定义一个配置类 @Configuration
2. 包扫描<context:component-scan />怎么办? 解决 @ComponentScan
3. dataSource和queryRunner怎么办? 解决 创建dataSource和queryRunner,存到Spring容器 @Bean
-->
<!--开启包扫描-->
<context:component-scan base-package="com.lovejava"></context:component-scan>
<!--注册dataSource: 1,创建了DruidDataSource 2,存到了Spring容器里面-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=utf8"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--注册queryRunner 1,创建了queryRunner 2,存到了Spring容器里面-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
</beans>
2.2配置类相关注解说明
2.2.1 @Configuration
-
作用:
用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。
获取容器时需要使用AnnotationApplicationContext(类.class)。
-
属性:
value:用于指定配置类的字节码
-
示例代码:
@Configuration
public class SpringConfiguration {
}
2.2.2 @ComponentScan
-
作用:
用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的:
<context:component-scan base-package="com.lovejava"/>
是一样的。 -
属性:
basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。
-
示例代码:
@Configuration
@ComponentScan("com.lovejava")
public class SpringConfiguration {
}
[email protected]
-
作用:
该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。
-
属性:
name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
-
示例代码:
/**
* 该类是一个配置类,它的作用和bean.xml是一样的
*/
@Configuration
@ComponentScan("com.lovejava")
public class SpringConfiguration {
private String driver = "com.mysql.jdbc.Driver";
private String url = "jdbc:mysql:///spring";
private String username = "root";
private String password = "root";
/**
* 用于创建一个QueryRunner对象
* @param dataSource
* @return
*/
@Bean("runner")
public QueryRunner createQueryRunner(@Qualifier(value ="dataSource") DataSource dataSource){
return new QueryRunner(dataSource);
}
/**
* 用于创建DataSource
* @return
* @throws PropertyVetoException
*/
@Bean(name = "dataSource")
public DataSource createDataSource() throws PropertyVetoException {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
}
}
[email protected]
-
作用:
用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题。
-
属性:
value[]:用于指定其他配置类的字节码。
-
示例代码:
/**
* 该类是一个配置类,它的作用和bean.xml是一样的
*/
@Configuration
@ComponentScan("com.lovejava")
@Import({JdbcConfig.class})
public class SpringConfiguration {
}
public class JdbcConfig {
private String driver = "com.mysql.jdbc.Driver";
private String url = "jdbc:mysql:///spring";
private String username = "root";
private String password = "root";
/**
* 用于创建一个QueryRunner对象
* @param dataSource
* @return
*/
@Bean("runner")
@Scope("prototype")
public QueryRunner createQueryRunner(@Qualifier(value ="dataSource") DataSource dataSource){
return new QueryRunner(dataSource);
}
/**
* 用于创建DataSource
* @return
* @throws PropertyVetoException
*/
@Bean(name = "dataSource")
public DataSource createDataSource() throws PropertyVetoException {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(driver);
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
}
}
[email protected]
-
作用:
用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。
-
属性:
value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
-
示例代码:
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root
JdbcConfig.java
@PropertySource(value = {"classpath:jdbc.properties"})
public class JdbcConfig {
@Value("${jdbc.url}")//引入了jdbc.properties配置文件中的属性
private String url;
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean("queryRunner")
public QueryRunner createQueryRunner(DataSource dataSource){
QueryRunner queryRunner = new QueryRunner(dataSource);
return queryRunner;
}
@Bean("dataSource")
public DataSource createDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(url);
dataSource.setDriverClassName(driver);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
2.3通过注解获取容器
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
四,Spring整合测试【会配置就行】
1.问题描述
在测试类中,每个测试方法都有以下两行代码:
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
AccountService as= ac.getBean("accountService");
这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。
2.解决方案
一般测试方法,都使用Junit 框架来测试, 其实在spring框架里面它也做出来了自己的一套测试逻辑, 里面是对junit进行了整合包装。在执行spring的单元测试上面,可以少写一些代码.
-
导入spring整合Junit的坐标
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency>
-
在测试类上面标记注解
@RunWith(SpringJUnit4ClassRunner.class)//指明运行的测试环境 //@ContextConfiguration("classpath:bean.xml")//指明spring框架的加载的配置文件【有applicationContext.xml解使用这种】 @ContextConfiguration(classes = SpringConfiguration.class)//指明spring框架的加载的配置类【纯注解使用这种】 public class DbTest { @Autowired private AccountService accountService; @Test public void testSaveAccount() throws Exception { Account account = new Account(); account.setName("圣弟压哥"); account.setMoney(100f); accountService.save(account); } }
3.为什么不把测试类配到xml中
-
在解释这个问题之前,先解除大家的疑虑,配到XML中没问题,可以使用。
-
那么为什么不采用配置到xml中,这个原因是这样的:
第一:当我们在xml中配置了一个bean,spring加载配置文件创建容器时,就会创建对象。
第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。
所以,基于以上两点,我们不应该把测试配置到xml文件中。
注解: 代替配置文件 开发方式
注册: 对象交给Spring创建
注入: 对象创建的同时, 依赖Spring给属性(字段)赋值
我的代码会发布在github,欢迎访问:https://github.com/MainPoser/spring-Demo/tree/master