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="">

2.1.1@Component

作用:
​ 把资源让 spring 来管理。相当于在 xml 中配置一个 bean。
属性:
​ value:指定 bean 的 id。如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写。

2.1.2@Controller @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.使用注解注入属性

3.1@Value
  • 作用:

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

  • 属性:

    value:用于指定值 , 可以通过表达式动态获得内容再赋值

  • 实例:

@Value("帕奇")
private String name;  
3.2@Autowired
  • 作用:

    ​ 自动按照类型注入。当使用注解注入属性时, 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();
    }
}
3.3@Qualifier
  • 作用

       在自动按照类型注入(@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();
    }
}
3.4@Resource

如果上面一个接口有多种实现,那么现在需要指定找具体的某一个实现,那么可以使用@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 {

}
2.2.3@Bean
  • 作用:

    该注解只能写在方法上,表明使用此方法创建一个对象,并且放入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;
    }

}
2.2.4@Import
  • 作用:

    用于导入其他配置类,在引入其他配置类时,可以不用再写@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;
    }


}
2.2.5@PropertySource
  • 作用:

    用于加载.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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值