Spring学习记录-02

本文深入解析Spring框架中IoC注解的使用,包括@Component、@Service、@Repository、@Controller、@Autowired、@Qualifier、@Resource、@Value、@Scope、@PostConstruct和@PreDestroy等注解的详细功能与应用场景,以及Spring纯注解配置和整合JUnit的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Spirng中IoC注解

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

    <!-- 告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为
    context名称空间和约束中 -->
    <context:component-scan base-package="cn.hyz"></context:component-scan>
    <!-- <context:annotation-config/> -->
</beans>

1.用于创建对象的注解

相当于:<bean id="" class="">
它们的作用和在xml配置文件中编写一个<bean>标签实现的功能是一样的

1.1. @Component

  • 作用:
    把当前类对象存入 Spring 容器中。相当于在 xml 中配置一个 bean。
  • 属性:
    value:指定 bean 的 id。如果不指定 value 属性,默认 bean 的 id 是当前类的类名。首字母小写
// 没有写value 默认值accountServiceImpl
@Component 
public class AccountServiceImpl implements IAccountService {

}
public class Client {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as = (IAccountService) ac.getBean("accountServiceImpl");
        System.out.println(as);
    }
}

1.2.@Controller @Service @Repository

以上三个注释它们的作用和属性与Component一模一样
它们三个是spring框架为我们提供明确的三层使用的注解,使用我们的三层对象更加清晰

  • @Controller:一般在用于表现层
  • @Service:一般用于业务层
  • @Repository:一般用在持久层

2.用于注入数据的注解

相当于:

<property name="" ref="">
<property name="" value="">

它们的作用和在 XML 配置文件的 bean 标签中编写一个 property 标签实现的功能是一样的(set方法注入)

2.1.@Autowired

  • 作用:自动根据类型注入,只要容器中有唯一一个bean对象类型和要注入的变量类型匹配,就可以注入成功。
  • 出现位置:可以是变量上,也可以是方法上
  • 细节:在使用注解注入时,set方法不是必须是用的
  • 特点:只能注入其他 bean 类型
/**
 * 账户的业务层实现类
 */

@Repository("accountDao1")
public class AccountDaoImpl implements IAccountDao {
    public void saveAccount() {
        System.out.println("保存了账户");
    }
}
/**
 * 账户的业务层实现类
 */

@Repository("accountDao2")
public class AccountDaoImpl2 implements IAccountDao {
    public void saveAccount() {
        System.out.println("保存了账户22");
    }
}
public class AccountServiceImpl implements AccountService {

  //    @Autowired
 //    @Qualifier("accountDao1")
       @Resource(name = "accountDao1")
       private IAccountDao accountDao1;
       
       public void saveAccount() {
         accountDao1.saveAccount();
}
  • 只有一个相符合的bean时,直接匹配数据类型
    只有一个bean
  • 有多个相匹配的bean时,先匹配数据类型,再根据 变量名称 与 bean的id 进行精确匹配
    多个bean
  • 如果IOC容器中有多个类型匹配时,此时注解不知道该用哪一个所以此时我们再加一个@Qualifier注解或者使用@Resource注解。

2.2.@Qualifier

  • 作用:
    在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。
    它在给字段注入时不能独立使用,必须和@Autowire 一起使用;但是给方法参数注入时,可以独立使用
  • 属性:
    value:指定 bean 的 id。
@Component
public class AccountServiceImpl implements IAccountService {

    @Autowired
    @Qualifier("accountDao1")
    private IAccountDao accountDao1;

    @Override
    public void saveAccount() {
        accountDao1.saveAccount();
    }
}

2.3.@Resource

  • 作用:
    直接按照 Bean 的 id 注入。它也只能注入其他 bean 类型。可以单独使用
  • 属性:
    name:指定 bean 的 id。
@Component
public class AccountServiceImpl implements IAccountService {
    @Resource(name = "accountDao2")
    private IAccountDao accountDao1;
    @Override
    public void saveAccount() {
        accountDao1.saveAccount();
    }
}

以上三个注入都只能注入其他bean类型数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过xml配置文件来实现

2.4.@Value

  • 作用:
    注入基本数据类型和 String 类型数据的
  • 属性:
    value:用于指定数据的值,可以使用Spring的SpEL(Spring的EL表达式)
  • SpEL表达式格式:${表达式}

3.用于改变作用范围的

相当于:<bean id="" class="" scope="">
它们的作用何在bean标签中使用scope属性实现的功能是一样的

3.1. @Scope

  • 作用:用于指定bean的作用范围
  • 属性:指定范围的取值。常用取值:singletonprototype

4.和生命周期相关的(扩展了解)

相当于:<bean id="" class="" init-method="" destroy-method="" />
他们的作用和在bean标签中使用init-methoddestroy-method的作用是一样的

4.1.@PostConstruct

  • 作用:指定初始化方法,放在方法上

4.2@PreDestory

  • 作用:指定销毁方法,放在方法上
@Service("accountService")
//@Scope("prototype")
public class AccountServiceImpl implements AccountService {

//    @Autowired
//    @Qualifier("accountDao1")
    @Resource(name = "accountDao1")
    private IAccountDao accountDao1;

    @PostConstruct
    public void init() {
        System.out.println("对象初始化了");;
    }

    @PreDestroy
    public void destroy() {
        System.out.println("对象销毁了");;
    }

    public void saveAccount() {
        accountDao1.saveAccount();
    }
}

二、Spring的纯注解配置

写到此处,基于注解的 IoC 配置已经完成,但是:我们依然离不开 spring 的 xml 配置文件,那么可否不写这个 bean.xml,完全使用注解来完成我们的配置?
需要特别注意的是我们选择哪种配置的原则是简化开发和配置方便,而非追求某种技术

1.待改造的问题

我们发现,之所以我们现在离不开 xml 配置文件,是因为我们有一句很关键的配置:

<!-- 告知spring框架在,读取配置文件,创建容器时,扫描注解,依据注解创建对象,并存入容器中 -->
<context:component-scan base-package="com.itheima"></context:component-scan>

如果他要也能用注解配置,那么我们就离脱离 xml 文件又进了一步。

另外,数据源和 JdbcTemplate 的配置也需要靠注解来实现。

<!-- 配置 dbAssit -->
<bean id="dbAssit" class="com.itheima.dbassit.DBAssit">
<property name="dataSource" ref="dataSource"></property>
</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:///spring_day02"></property>
<property name="user" value="root"></property>
<property name="password" value="1234"></property>
</bean>

2.新注解说明

2.1.@Configuration

  • 作用:
    用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(@Configuration 注解的类.class)。
  • 属性:
    value:用于指定配置类的字节码
  • 细节:当配置类作为 AnnotationConfigApplicationContext 对象创建的参数时,该注解可以不写
@Configuration
public class SpringConfiguration {

}

2.2.@ComponentScan

  • 作用:用于通过注解指定spring在创建容器时要扫描的包
  • 属性:
    value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包
  • 我们使用此注解就等同于在xml中配置了:
    <context:component-scan base-package="cn.hyz"></context:component-scan>
 @Configuration
 @ComponentScan("cn.hyz")
 public class SpringConfiguration {

}

2.3.@Bean

  • 作用:用于把当前方法的返回值作为bean对象存入spring的IOC容器中
  • 属性:
    name:用于指定bean的id,默认值是当前方法的名称
  • 细节:当我们使用注解配置方法是,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象,查找的方式和@Autowired注解的作用是一样的
/**
 * 连接数据库的配置类  
 */ 
@Configuration 
@ComponentScan("com.smallbeef") 
public class JDBCConfiguration {

    /**
     * 创建一个数据源,并存入 spring 容器中   
     * * @return   
     * */  
    @Bean(name="dataSource")  
    public DataSource createDataSource() {   
        try {    
            ComboPooledDataSource ds = new ComboPooledDataSource();    
            ds.setUser("root");    
            ds.setPassword("1234");    
            ds.setDriverClass("com.mysql.jdbc.Driver");
            ds.setJdbcUrl("jdbc:mysql:///spring_day02");    
            return ds;   
        } catch (Exception e) {    
            throw new RuntimeException(e);   
        }  
    }

    /**
     * 创建一个 QuerryRunner对象,并且也存入 spring 容器中   
     * * @param dataSource   
     * * @return   
     * */  
    @Bean(name="dbAssit")  
    public  DBAssit createDBAssit(DataSource dataSource) {   
        return new  DBAssit(dataSource);  
    }  
} 

我们已经把数据源和 DBAssit 从配置文件中移除了,此时可以删除 bean.xml 了。
但是由于没有了配置文件,创建数据源的配置又都写死在类中了。

2.4.@PropertySource

  • 作用:用于加载.properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。
  • 属性:
    value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:
    在下面的代码中可以看到数据库的配置是写死的
  @Bean(name="dataSource")  
    public DataSource createDataSource() {   
        try {    
            ComboPooledDataSource ds = new ComboPooledDataSource();    
            ds.setUser("root");    
            ds.setPassword("1234");    
            ds.setDriverClass("com.mysql.jdbc.Driver");
            ds.setJdbcUrl("jdbc:mysql://localhost:3306/day44_ee247_spring");    
            return ds;   
        } catch (Exception e) {    
            throw new RuntimeException(e);   
        }  
    }

我们将数据库配置放在 .properties 文件中,利用 @PropertySource 注解读取该文件,并用 @Value 注解传值
jdbcConfig.properties

jdbc.driver=com.mysql.jdbc.Driver  
jdbc.url=jdbc:mysql://localhost:3306/day44_ee247_spring 
jdbc.username=root 
jdbc.password=1234

利用@Value传值

/**
 * 连接数据库的配置类  
 */ 
@Configuration 
@ComponentScan("com.smallbeef") 
public class JDBCConfiguration {
	@Value("${jdbc.driver}")  //与properties中属性一致
	private Stirng driver;
	
	@Value("${jdbc.url}")
	private String url;
	
	@Value("${jdbc.username}")
	private String username;
	
	@Value("${jdbc.password}")
	private String password;
	
    /**
     * 创建一个数据源,并存入 spring 容器中   
     * * @return   
     * */  
    @Bean(name="dataSource")  
    public DataSource createDataSource() {   
        try {    
            ComboPooledDataSource ds = new ComboPooledDataSource();    
            ds.setUser("username");    
            ds.setPassword("password");    
            ds.setDriverClass("driver");
            ds.setJdbcUrl("url");    
            return ds;   
        } catch (Exception e) {    
            throw new RuntimeException(e);   
        }  
    }

    /**
     * 创建一个 QuerryRunner对象,并且也存入 spring 容器中   
     * * @param dataSource   
     * * @return   
     * */  
    @Bean(name="dbAssit")  
    public  DBAssit createDBAssit(DataSource dataSource) {   
        return new  DBAssit(dataSource);  
    }  
} 

2.5.@Import

  • 作用:
    用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration 注解。
  • 属性:
    value[]:用于指定其他配置类的字节码。
    当我们使用Import注解之后,有Import注解的类就是父配置类,导入的都是子配置类
  • 示例代码:
@Configuration
@ComponentScan(basePackages = "com.itheima.spring")
@Import({ JdbcConfig.class})
public class SpringConfiguration {
}
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig{
}

3.通过注解获取容器

ApplicationContext ac =
new AnnotationConfigApplicationContext(SpringConfiguration.class);

4.关于 Spring 注解和 XML 的选择问题

  • 注解的优势:
    配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。
  • XML 的优势:
    修改时,不用改源码。不涉及重新编译和部署
  • Spring 管理 Bean 方式的比较:
  • 注解和配置文件比较

三、Spring整合Junit(必须掌握)

问题
在测试类中,每个测试方法都有以下两行代码:

ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountService as = ac.getBean("accountService",IAccountService.class);

这两行代码的作用是获取容器,如果不写的话,直接会提示空指针异常。所以又不能轻易删掉。

1.Spring整合Junit配置

  1. 第一步:拷贝整合 junit 的必备 jar 包到 lib 目录
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-test</artifactId>
	<version>5.0.2.RELEASE</version>
</dependency>

//当我们使用spring5.x版本的时候,要求junit的jar包必须是4.12及以上
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
</dependency>
  1. 第二步:使用@RunWith 注解替换原有运行器
/**
* 测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class AccountServiceTest {
}
  1. 第三步:使用@ContextConfiguration 指定 spring 配置文件的位置
  • @ContextConfiguration 注解:
  • locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明
  • classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。
/**
* 测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:bean.xml"})
public class AccountServiceTest {
}
  1. 第四步:使用@Autowired 给测试类中的变量注入数据
/**
* 测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:bean.xml"})
public class AccountServiceTest {
@Autowired
private IAccountService as ;
}

2.为什么不把测试类配到 xml 中

原因是因为:
第一:当我们在 xml 中配置了一个 bean,spring 加载配置文件创建容器时,就会创建对象。
第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。

所以,基于以上两点,我们不应该把测试配置到 xml 文件中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值