Spring学习第二天:Spring的注解开发

本文涉及的产品
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: Spring学习第二天:Spring的注解开发

文章目录

准备工作

持久层创建

在com/spring/dao包下创建IaccountDao接口

内容:

package com.spring.dao;
public interface IaccountDao {
    public void saveUser();
}

在com/spring/dao/impl包下创建AccountDaoImpl类

package com.spring.dao.impl;
import com.spring.dao.IaccountDao;
import org.springframework.stereotype.Repository;
public class AccountDaoImpl implements IaccountDao {
    public void saveUser() {
        System.out.println("保存成功");
    }
}

业务层创建

在com/spring/server包下创建IAccountserver接口

package com.spring.server;
public interface IAccountserver {
    public void saveAccount();
}

在com/spring/server/impl包下创建Accountserverimpl类

package com.spring.server.impl;
public class Accountserverimpl implements IAccountserver {
    private IaccountDao dao ;
    public Accountserverimpl() {
        System.out.println("accountserverimpl"+"被创建了");
    }
    @Override
    public void saveAccount() {
        dao.saveUser();
    }
}

表示层创建

package com.spring;
import com.spring.server.IAccountserver;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
    public static void main(String[] args){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //根据id获取对象
        IAccountserver accountserver=(IAccountserver)ac.getBean("acServer");
        accountserver.saveAccount();
    }
}

更改配置文件

改变bean.xml

<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.spring"/>
</beans>

注解:

注解大体可以分为四类

1.创建对象 ---- 对应xml中的bean标签

2.注入数据 ---- 对应xml中的property标签

3.改变作用范围(多例,单例 ,request ,session ,global—session) ---- 对应xml中的scope属性

4.和生命周期相关 ---- 对应xml中的init-method和destroy-method

创建对象的注解

Component:

属性:

value:用于指定类的id:当此属性是空的时,id为首字母改为小写的类名,

以下三个注解功能和Component相同 只是针对不同的层级提供了不同的名称,以便区分

Controller:一般用于表现层

Service:一般用于业务层

Repository:一般用于持久层

可以试一下对Accountserverimpl类做出以下修改

@Service(value = "acServer")
public class Accountserverimpl implements IAccountserver {
    private IaccountDao dao ;
    public Accountserverimpl() {
        System.out.println("accountserverimpl"+"被创建了");
    }
    @Override
    public void saveAccount() {
        dao.saveUser();
    }
}

主函数:

    public static void main(String[] args){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //根据id获取对象
        IAccountserver accountserver=(IAccountserver)ac.getBean("acServer");
        System.out.println(accountserver);
    }

此时运行即可看到结果

image.png

同样给AccountDaoImpl添加注解 以便后面的使用

@Repository(value = "AD")
public class AccountDaoImpl implements IaccountDao {
    @Override
    public void saveUser() {
        System.out.println("保存成功");
    }
}

注入数据注解

Autowired:(此注解只能够自动注入)

          作用:自动按照类型注入,只要容器中有一个bean对象和要注入的类型匹配就可以注入
                若ioc容器中没有任何一个类型与其匹配则注入失败
                若ioc容器中有多个匹配项则先根据需要注入变量的数据名称来注入
           出现位置:成员变量或方法上

Qualifier

           作用:按照类型注入的基础上再按照名称注入 在给类成员注入时不能单独使用,但在方法传参时可以单独使用
           属性:
               value:用于指定注入bean的id

这时我们更改以下主类让其调用save方法

Resource

  作用:按照类型注入的基础上再按照id注入,可以单独使用
  属性:name:传入id
  《--------------------------以上三个标签都只能注入bean数据类型而不能注入基本数据类型和string---------------------------------》

value

  作用:基本数据类型和string的注入
  属性:
      value:用于指定数据的值 可以使用spel
        spel的写法:${表达式}

演示:

public static void main(String[] args){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //根据id获取对象
        IAccountserver accountserver=(IAccountserver)ac.getBean("acServer");
        System.out.println(accountserver);
        accountserver.saveAccount();
    }

此时运行会发现出现了空指针异常

原因很明显Accountserverimpl中的dao没有初始化

那么我们就要对dao进行注入

这里使用@Autowired注解

Service(value = "acServer")
public class Accountserverimpl implements IAccountserver {
    @Autowired
    private IaccountDao dao ;
    public Accountserverimpl() {
        System.out.println("accountserverimpl"+"被创建了");
    }
    @Override
    public void saveAccount() {
        dao.saveUser();
    }
}

此时便可以成功运行

由此可知@Autowired是通过数据类型在ioc容器中查找对应数据类型来注入的

但是又出现了新的问题,如果同时存在两个IaccountDao 的实现类,那spring会注入哪个呢

可以试一下:

我们复制一份AccountDaoImpl,取名AccountDaoImpl2

更改@Repository(value = "AD")@Repository(value = "AD2")此时再次运行主程序便会报错

这是因为同时有两个bean拥有相同数据类型时,spring不知道你想要的具体是哪个对象,我们有两种方式进行修改:

  1. 修改类中的变量名称使其与ioc容器中的id相同(显然不是什么好方法)
  2. 使用@Qualifier注解
    @Qualifier注解在给类成员变量进行注入时需要与@Autowired配合使用

如:

@Service(value = "acServer")
public class Accountserverimpl implements IAccountserver {
    @Autowired
    @Qualifier("AD2")
    private IaccountDao dao ;
    public Accountserverimpl() {
        System.out.println("accountserverimpl"+"被创建了");
    }
    @Override
    public void saveAccount() {
        dao.saveUser();
    }
}

此时便可以正常运行,并获取到你想要的bean

但用两个注解是不是繁琐了一点

这里便有了Resource注解

我们使用@Resource(name = "AD")@Resource(name = "AD2")注解来实现功能

即:

public class Accountserverimpl implements IAccountserver {
    @Resource(name = "AD2")
    private IaccountDao dao ;
    public Accountserverimpl() {
        System.out.println("accountserverimpl"+"被创建了");
    }
    @Override
    public void saveAccount() {
        dao.saveUser();
        System.out.println(s);
    }
}

!!----------------------注意以上三个注解只能注入bean对象而不能注入基本数据类型和String--------------------------!!

这时我们在Accountserverimpl中添加一个私有string类型的变量

我们可以通过value注解进行注入

@Service(value = "acServer")
@Scope(value = "prototype")
public class Accountserverimpl implements IAccountserver {
    @Resource(name = "AD2")
    private IaccountDao dao ;
    @Value(value = "hello")
    private String s;
    public Accountserverimpl() {
        System.out.println("accountserverimpl"+"被创建了");
    }
    @Override
    public void saveAccount() {
        dao.saveUser();
        System.out.println(s);
    }
}

此时调用saveAccount即可看见

image.png

改变作用范围

(singleton,prototype ,request ,session ,global—session) ---- 对应xml中的scope属性

Scope 与创建对象标签一起使用

作用:与xml中的scope属性一致

属性:value 传入singleton,prototype ,request ,session ,global—session

@Service(value = "acServer")
@Scope(value = "prototype")
public class Accountserverimpl implements IAccountserver {
    @Resource(name = "AD2")
    private IaccountDao dao ;
    @Value(value = "hello")
    private String s;
    public Accountserverimpl() {
        System.out.println("accountserverimpl"+"被创建了");
    }
    @Override
    public void saveAccount() {
        dao.saveUser();
        System.out.println(s);
    }
}

此时更改主程序

public class Test {
    public static void main(String[] args){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //根据id获取对象
        IAccountserver accountserver=(IAccountserver)ac.getBean("acServer");
        IAccountserver accountserver2=(IAccountserver)ac.getBean("acServer");
        System.out.println(accountserver==accountserver2);
//        accountserver.saveAccount();
    }
}

即可看见运行结果,已经成功的变为多例

image.png

生命周期注解

@PostConstruct 指定初始化函数

@PreDestroy指定销毁函数

@Service(value = "acServer")
public class Accountserverimpl implements IAccountserver {
    @Resource(name = "AD2")
    private IaccountDao dao ;
    @Value(value = "hello")
    private String s;
    public Accountserverimpl() {
        System.out.println("accountserverimpl"+"被创建了");
    }
    @Override
    public void saveAccount() {
        dao.saveUser();
        System.out.println(s);
    }
    @PostConstruct
    public void init(){
        System.out.println("初始化");
    }
    @PreDestroy
    public void end(){
        System.out.println("对象销毁");
    }
}

配置文件注解:

在前面的这些注解中能够大部分的去除对xml的依赖,但仍无法脱离xml

比如创建jar包中类的bean就不太可能,所以我们有了下面这些注解

Configuration和ComponentScar

Configuration

作用:指定当前类是一个配置类

ComponentScar

作用:用于通过注解指定spring在创建容器时要扫描的包

属性

value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。

我们使用此注解就等同于在xmL中配置了:<context: component-scan base-package=“com.itheima”></context: component-scan>

@Configuration
@ComponentScan("com.spring")
public class SpringConfig {
}

这样就可以声明一个配置类了

bean

Bean

作用:用于把当前方法的返回值作为bean对象存入spring的ioc器中

属性:

name:用于指定bean的id,当不写时,默认值是当前方法的名称

当我们使用注解配置方法时,如果方法有参数, spring框架会去容器中查找有没有可用的bean对象。查找的方式和Autoviredi解的作用是一样的 当我们要指定容器中bean的id时,使@Qualifier注解

@Configuration
@ComponentScan("com.spring")
public class SpringConfig {
    @Bean
    @Scope("prototype")
    public QueryRunner createQueryRunner(@Qualifier("ds1") DataSource dataSource){
        return new QueryRunner(dataSource);
    }
    @Bean(name="ds1")
    public  DataSource createDataSource(){
        try {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_test");
            dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
            dataSource.setUser("root");
            dataSource.setPassword("adminadmin");
            return dataSource;
        }
        catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

可以看见Bean注解是可以和Scope配合使用的

import

import

作用:导入其他配置类

属性:

Class<?>[] value() 传入一个或多个类的句柄(.class)有impact注解的为主配置,而其他为子配置类

PropertySource

PropertySource

作用:读取properties配置文件

属性:

value:指定文件名称和路径。

关键字:classpath 表示在类路径下

示例:

由于前面获取参数的方式过于粗暴

我们就可以使用PropertySource来获取参数

image.png

首先创建jdbcconfig.properties

jdbc.url=jdbc:mysql://localhost:3306/spring_test
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=adminadmin

然后在SpringConfig文件里做修改

@Configuration
@ComponentScan("com.spring")
@PropertySource("classpath:jdbcconfig.properties")
public class SpringConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.user}")
    private String user;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.url}")
    private String url;
    @Bean
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource){
        return new QueryRunner(dataSource);
    }
    @Bean
    public  DataSource createDataSource(){
        try {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setJdbcUrl(url);
            dataSource.setDriverClass(driver);
            dataSource.setUser(user);
            dataSource.setPassword(password);
            return dataSource;
        }
        catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

此时注解就调用成功了

在junit中调试时

在测试类中,如果需要使用spring直接写注解是无法使用的,我们首先需要导入依赖

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.10</version>
        </dependency>

在测试类加入

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class DbutilTest {
    @Autowired
    private IAccountService service;
    @Test
    public void testFindAll() {
}

此时在测试类中才能正常使用spring

总结

我们在注解配置时,并没有说所有情况变得更加方便,反而在对jar包配置时更加繁琐,所以在实际开发中,我们通常采用xml和注解相结合的方式来进行的,哪个方便就用哪个。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4天前
|
XML Java 测试技术
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
这篇文章介绍了Spring5框架的三个新特性:支持@Nullable注解以明确方法返回、参数和属性值可以为空;引入函数式风格的GenericApplicationContext进行对象注册和管理;以及如何整合JUnit5进行单元测试,同时讨论了JUnit4与JUnit5的整合方法,并提出了关于配置文件加载的疑问。
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
|
4天前
|
人工智能 自然语言处理 Java
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
文章介绍了Spring AI,这是Spring团队开发的新组件,旨在为Java开发者提供易于集成的人工智能API,包括机器学习、自然语言处理和图像识别等功能,并通过实际代码示例展示了如何快速集成和使用这些AI技术。
Spring AI,Spring团队开发的新组件,Java工程师快来一起体验吧
|
3天前
|
Java 数据安全/隐私保护 Spring
揭秘Spring Boot自定义注解的魔法:三个实用场景让你的代码更加优雅高效
揭秘Spring Boot自定义注解的魔法:三个实用场景让你的代码更加优雅高效
|
4天前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
4天前
|
XML 数据库 数据格式
Spring5入门到实战------14、完全注解开发形式 ----JdbcTemplate操作数据库(增删改查、批量增删改)。具体代码+讲解 【终结篇】
这篇文章是Spring5框架的实战教程的终结篇,介绍了如何使用注解而非XML配置文件来实现JdbcTemplate的数据库操作,包括增删改查和批量操作,通过创建配置类来注入数据库连接池和JdbcTemplate对象,并展示了完全注解开发形式的项目结构和代码实现。
Spring5入门到实战------14、完全注解开发形式 ----JdbcTemplate操作数据库(增删改查、批量增删改)。具体代码+讲解 【终结篇】
|
4天前
|
XML Java 数据格式
Spring5入门到实战------8、IOC容器-Bean管理注解方式
这篇文章详细介绍了Spring5框架中使用注解进行Bean管理的方法,包括创建Bean的注解、自动装配和属性注入的注解,以及如何用配置类替代XML配置文件实现完全注解开发。
Spring5入门到实战------8、IOC容器-Bean管理注解方式
|
4天前
|
设计模式 Java 测试技术
公司为何禁止在SpringBoot中使用@Autowired注解?
【8月更文挑战第15天】在Spring Boot的广泛应用中,@Autowired注解作为依赖注入的核心机制之一,极大地简化了Bean之间的装配过程。然而,在某些企业环境下,我们可能会遇到公司政策明确禁止或限制使用@Autowired注解的情况。这一决策背后,往往蕴含着对代码质量、可维护性、测试便利性以及团队开发效率等多方面的考量。以下将从几个方面深入探讨这一决定的合理性及替代方案。
10 0
|
4天前
|
XML Java 数据库
Spring5入门到实战------10、操作术语解释--Aspectj注解开发实例。AOP切面编程的实际应用
这篇文章是Spring5框架的实战教程,详细解释了AOP的关键术语,包括连接点、切入点、通知、切面,并展示了如何使用AspectJ注解来开发AOP实例,包括切入点表达式的编写、增强方法的配置、代理对象的创建和优先级设置,以及如何通过注解方式实现完全的AOP配置。
|
22天前
|
Java 测试技术 数据库
Spring Boot中的项目属性配置
本节课主要讲解了 Spring Boot 中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。最后介绍了开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。