Spring框架

第一章 注解与包扫描

1.1 注解的作用

和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。

本质上:所有一切的操作都是Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行。

Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注解进行后续操作。

1.2 创建项目中的不同组件类

  1. package com.atguigu.ioc.component;
  2. public class CommonComponent {
  3. }
package com.atguigu.ioc.component;
public class HelloController {
}
package com.atguigu.ioc.component;
public class HelloService {
}
package com.atguigu.ioc.component;
public class HelloDao {
}

1.3 bean标签和注解的对应关系

  • bean标签对应注解@Component
    • 注解属性value:bean标签的id属性
    • 不指定value属性,默认就是类名,首字母小写
    • 该注解衍生出了三个注解,@Controller,@Service,@Repository,用法和@Componet一致,为了更加清晰的提现层的概念。
    • @Controller作用于表现层
    • @Service作用于业务层
    • @Repository作用于持久层
  • bean标签属性scope对应注解@Scope
    • 注解属性value:singleton,prototype

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

    <!-- 开启spring的注解扫描,扫描包中类的注解-->
    <context:component-scan base-package="com.atguigu.ioc.component"/>
</beans>

在相应的组件类上添加注解并测试

public void testAnnotationcScanBean() {
    CommonComponent commonComponent = iocContainer.getBean(CommonComponent.class);

    HelloController HelloController = iocContainer.getBean(HelloController.class);

    HelloService HelloService = iocContainer.getBean(HelloService.class);

    HelloDao HelloDao = iocContainer.getBean(HelloDao.class);

    System.out.println("commonComponent = " + commonComponent);
    System.out.println("HelloController = " + HelloController);
    System.out.println("HelloService = " + HelloService);
    System.out.println("HelloDao = " + HelloDao);
}

1.5 注解属性value

@Controller,@Service,@Repository,和@Componet 注解的属性value

在我们使用XML方式管理bean的时候,每个bean都有一个唯一标识,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。

类名首字母小写就是bean的id。例如:HelloController类对应的bean的id就是helloController。

@Controller(value = "xxx")
public class HelloController {
}

第二章 SpringIOC实现数据表操作

1.1 实现思想

  • maven工程引入坐标
    • junit
    • mysql驱动
    • druid数据库连接池
    • dbutils数据库工具
    • dao层service层涉及到很多对象的管理(Spring-context)
  • 开发步骤分析
    • 引入坐标(如上)
    • Account表的pojo开发
    • 开发dao层代码(dao接口和实现类)
    • 在dao实现类当中使用dbutils操作数据库
    • sevice层开发
    • 上述过程中涉及到的对象和对象之间的引用注入交给Spring管理

1.2 配置德鲁伊连接池

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

1.3 配置dao层和service层对象

public interface AccountDao {
    void addAccount(Account account) throws SQLException;
}
public class AccountDaoImpl implements AccountDao {
    private QueryRunner qr ;

    public void setQr(QueryRunner qr) {
        this.qr = qr;
    }
    @Override
    public void addAccount(Account account) throws SQLException {
        qr.update("insert into account values(?,?,?)",account.getName(),account.getMoney());
    }
}
public interface AccountService {
    void addAccount(Account account);
}
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void addAccount(Account account) {
        try {
            accountDao.addAccount(account);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
<bean class="org.apache.commons.dbutils.QueryRunner" id="queryRunner">
    <constructor-arg name="ds" ref="dataSource"/>
</bean>
<bean class="com.atguigu.dao.impl.AccountDaoImpl" id="accountDao">
    <property name="qr" ref="queryRunner"/>
</bean>
<bean class="com.atguigu.service.impl.AccountServiceImpl" id="accountService">
    <property name="accountDao" ref="accountDao"/>
</bean>

1.4 测试程序

@Test
public void test(){
    ApplicationContext applicationContext =
    new ClassPathXmlApplicationContext("applicationContext.xml");
    AccountService accountService = applicationContext.getBean(AccountService.class);
    Account account = new Account();
    account.setName("tom");
    account.setMoney(10000D);
    accountService.addAccount(account);
}

第三章 数据表操作半注解半xml改进

1.1 @Autowired注解

@Autowired自动装配注解:

按照类型注入,如果无法确定唯一类型(接口有多个实现类),需要配合注解@Qualifier的使用,@Qualifier(“id”)。

注解注入,不要setXXX方法。

首先根据所需要的组件类型到IOC容器中查找

  • 能够找到唯一的bean:直接执行装配
  • 如果完全找不到匹配这个类型的bean:装配失败
  • 和所需类型匹配的bean不止一个
    • 没有@Qualifier注解:根据@Autowired标记位置成员变量的变量名作为bean的id进行匹配
      • 能够找到:执行装配
      • 找不到:装配失败
    • 使用@Qualifier注解:根据@Qualifier注解中指定的名称作为bean的id进行匹配
      • 能够找到:执行装配
      • 找不到:装配失败

1.2 半注解半xml改造

企业开发的主流

注意:往往第三方jar中的对象我们使用xml配置(比如druid数据库连接池、dbutils的QueryRunner),类似于service层和dao层的实现类,这属于我们自己写的代码,往往会使用注解,这就是半xml半注解的模式。

  • applicationContext.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
">
    <!-- 开启Spring的注解扫描-->
    <context:component-scan base-package="com.atguigu"/>
    <!-- 配置dbcp连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    <!-- 配置QueryRunner对象-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
        <constructor-arg ref="basicDataSource"></constructor-arg>
    </bean>
</beans>
  • service层
@Service("accountService")
public class AccountServiceImpl implements AccountService {
    @Autowired
    @Qualifier("accountDao")
    private AccountDao accountDao;

    @Override
    public void saveAccount(Account account) {
        try {
            accountDao.saveAccount(account);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
  • dao层
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
    @Autowired
    @Qualifier("queryRunner")
    private QueryRunner qr;

    @Override
    public void saveAccount(Account account) throws SQLException {
        String sql = "insert into account values(?,?,?)";
        qr.update(sql,null,account.getName(),account.getMoney());
    }
}
  • 测试程序
public void testSaveAccount(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    AccountService service = context.getBean("accountService", AccountService.class);
    Account account = new Account();
    account.setName("testName");
    account.setMoney(0.99);
    service.saveAccount(account);
}

1.3 @Resource注解

@Resource注解(JDK提供)

  • 注解属性name:配置类的id
@Resource(name="accountDao")
private AccountDao accountDao;

第四章 数据表操作纯注解改造

体验完全注解开发,是为了给将来学习SpringBoot打基础。因为在SpringBoot中,就是完全舍弃XML配置文件,大部分使用注解来完成主要的配置。

1.1 纯注解开发中的相关注解

  • @Configuration标识当前类是Spring的一个配置类
  • @ComponentScan替代xml中的<context:component-scan/>
  • @Import引入其他配置类,被引入的配置类可以不加@Configuration注解
  • @PropertySource:引入外部properties文件,注意加classpath:
  • @Value对成员变量赋值
  • @Bean将一个方法的返回值对象加入到Spring的容器当中管理
  • @Qualifier可以使用在方法上,表明对应的形参引入/注入的对象类型

1.2 Spring配置类SpringConfig

//Spring配置类,框架启动入口
@Configuration
//启动注解扫描
@ComponentScan({"com.atguigu"})
public class SpringConfig {

    //方法的返回值,加入到SpringIOC容器中管理
    @Bean("basicDataSource")
    public DataSource createDataSource(){
        DruidDataSource basicDataSource = new DruidDataSource();
        basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        basicDataSource.setUrl("jdbc:mysql://localhost:3306/test");
        basicDataSource.setUsername("root");
        basicDataSource.setPassword("root");
        return basicDataSource;
    }
    //方法的返回值,加入到SpringIOC容器中管理
    @Bean("queryRunner")
    //@Qualifier("basicDataSource"),对参数进行注入
    public QueryRunner createQueryRunner( @Qualifier("basicDataSource") DataSource ds){
        QueryRunner queryRunner = new QueryRunner(ds);
        return  queryRunner;
    }
}

1.3 业务层和持久层

  • dao层

    @Repository("accountDao")
    public class AccountDaoImpl implements AccountDao {
     @Autowired
     @Qualifier("queryRunner")
     private QueryRunner qr;
    
     @Override
     public void saveAccount(Account account) throws SQLException {
         String sql = "insert into account values(?,?,?)";
         qr.update(sql,null,account.getName(),account.getMoney());
     }
    }
    
  • service层

    @Service("accountService")
    public class AccountServiceImpl implements AccountService {
     @Autowired
     @Qualifier("accountDao")
     private AccountDao accountDao;
    
     @Override
     public void saveAccount(Account account) {
         try {
             accountDao.saveAccount(account);
         } catch (SQLException e) {
             e.printStackTrace();
         }
     }
    }
    
  • 测试
    ```java @Test public void testAnnotation() { ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); AccountService service = context.getBean(“accountService”, AccountService.class); Account account = new Account(); account.setName(“testAnnoName”); account.setMoney(1.98); service.saveAccount(account);

}


<a name="ee476ba6"></a>
## 1.4 注解开发的SpringConfig配置优化

-  SpringConfig框架启动配置类  
```java
//Spring配置类,框架启动入口
@Configuration
//启动注解扫描
@ComponentScan({"com.atguigu"})
//引入JDBC的配置类
@Import({JDBCConfig.class})
public class SpringConfig {
}
  • JDBCConfig配置类

    @Configuration
    @PropertySource("classpath:jdbc.properties")
    public class JDBCConfig {
    
     //注入配置文件中的键值对
     @Value("${jdbc.driver}")
     private String driverClassName;
    
     @Value("${jdbc.url}")
     private String url;
    
     @Value("${jdbc.username}")
     private String username;
    
     @Value("${jdbc.password}")
     private String password;
    
     //方法的返回值,加入到SpringIOC容器中管理
     @Bean("basicDataSource")
     public DataSource createDataSource(){
         BasicDataSource basicDataSource = new BasicDataSource();
         basicDataSource.setDriverClassName(driverClassName);
         basicDataSource.setUrl(url);
         basicDataSource.setUsername(username);
         basicDataSource.setPassword(password);
         return basicDataSource;
     }
     //方法的返回值,加入到SpringIOC容器中管理
     @Bean("queryRunner")
     //@Qualifier("basicDataSource"),对参数进行注入
     public QueryRunner createQueryRunner(@Qualifier("basicDataSource") DataSource ds){
         QueryRunner queryRunner = new QueryRunner(ds);
         return  queryRunner;
     }
    }
    

1.5 Spring框架对junit的支持

  • junit运行的时候底层使用了Runner对象,有一个默认使用的Runner对象。
  • Spring对junit的支持,其实是自己实现了一个Runner对象(按照junit runner的要求实现)
  • Spring对junit的支持的体现
    • 好处一:配置完之后,不需要我们手动的启动Spring,而是会很方便的启动Spring
    • 好处二:可以在junit测试类中使用@AutoWired等方式注入对象,直接对其进行调用测试
  • 使用步骤
    • 引入jar
    • 配置你的测试类
//Spring框架中的Runner对象,替换Junit中的runner对象
@RunWith(SpringJUnit4ClassRunner.class)

//框架启动入口,配置类启动
@ContextConfiguration(classes = SpringConfig.class)

//框架启动入口,xml配置文件启动
//@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class MainTest 
{
    //注入业务层接口
    @Autowired
    @Qualifier("accountService")
    private AccountService service;


    @Test
    public void testAnnotation() {

        Account account = new Account();
        account.setName("testAnnoName3");
        account.setMoney(3.98);
        service.saveAccount(account);

    }
}