首页 > 其他分享 >Spring注解开发

Spring注解开发

时间:2024-10-21 17:17:41浏览次数:5  
标签:userDao Spring void bean 开发 println 注解 public

前言

从spring2.0开始,spring逐步提供了各种各样的注解,到了spring2.5注解就比较完善了,到了spring3.0就是纯注解开发

使用注解进行开发可以简化开发步骤,提升开发效率,但是我们需要了解底层原理,接下来我将介绍如何使用Spring的注解来简化开发。

 注解开发定义bean

 使用注解定义bean和在xml配置文件中定义bean的效果是相同的,只不过是一种方式的不同表现,因此它们应当具有相同或相似的结构。

准备工作

第一步:创建maven项目,添加依赖

pom.xml
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

第二步:接口和实体类

UserDao

public interface UserDao {

    public void say();
}

UserDaoImpl

@Component("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void say() {
        System.out.println("UserDaoImpl start...");
    }
}

UserService

public interface UserService {
    public void  say();
}

UserServiceImpl

第三步:创建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>	
	

我这个spring配置文件,包含了基本的spring配置头信息,包括了context命名空间,但是不包括aop的命名空间。 

第四步:创建测试类

APP
/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        ApplicationContext context =new ClassPathXmlApplicationContext("spring.xml");
        UserDao userDao = (UserDao) context.getBean("userDao");
        userDa.say();
    }
}

使用xml定义bean

使用xml配置文件,需要定义<bean>标签

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


    <bean id="userDaoImpl" class="org.example.dao.impl.UserDaoImpl"/>

</beans>	
	

使用注解定义bean

使用注解定义bean,本质上就是使用注解代替<bean>标签,完成bean的定义的方式

 第一步:在spring.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="org.example"/>

    
</beans>	
	
  • 无论是xml定义bean还是注解定义bean,本质上都是spring容器启动后扫描spring的配置文件来进行bean的定义和初始化的,因此spring配置文件需要保留,但是由于定义一堆配置既麻烦又不简洁,因此出现了注解代替<bean>标签的配置方式。
  • 开启注解扫描之后,我们可以扫描spring中的注解。
  • base-package后面跟的是包名的话可以扫描当前包及其子包中是否存在注解

第二步:在要管理的实体类上加上@Component注解

 UserDaoImpl
@Component("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void say() {
        System.out.println("UserDaoImpl start...");
    }
}
  • 此时就不需要定义<bean>标签了
  • 如果使用注解不提供名字(与配置文件中bean标签的id相似),则需要使用类型进行获取对应的bean对象。

 纯注解开发

  • Spring3.0升级了纯注解开发模式,使用Java类代替配置文件,开启Spring快速开发赛道
  • 为了变成纯注解的开发模式,xml配置文件就需要里面没有其他多余代码,因此需要换一种形式表现xml配置文件中的扫描注解的标签,在java代码中主要书写的是类,因此可以用类来替代配置文件(简单理解,就是使用配置类代替配置文件,完成bean的定义)

 第一步:将spring.xml删除

其实也不用删除,不使用即可,将后缀改为bak

 

第二步:声明Java配置类

SpringConfig

@Configuration
@ComponentScan("org.example")
public class SpringConfig {

}
  • @Configuration注解声明一个类,这个类的作用就和spring.xml文件的作用是一样的了
    • @Configuration注解用于设定当前类为配置类
  • @ComponentScan注解,实际上就是代替spring.xml配置文件中的开启扫描配置
    • @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式

 可以理解为使用一个Java类代替了xml配置文件,它俩起的作用是一样的。

基于注解的bean管理 

  • 在实体类上方添加@Scope注解,主要的参数有
    • singleton:单例
    • prototype:多例

 单例

@Scope("singleton")
@Component("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void say() {
        System.out.println("UserDaoImpl start...");
    }
}

使用的bean是同一个 

public class App 
{
    public static void main( String[] args )
    {

        ApplicationContext context =new AnnotationConfigApplicationContext(SpringConfig.class);
        UserDao userDao = (UserDao) context.getBean("userDao");
        UserDao userDao1 = (UserDao) context.getBean("userDao");
        System.out.println(userDao);
        System.out.println(userDao1);
    }
}

 测试效果:

地址相同,为同一个bean对象

多例

@Scope("prototype")
@Component("userDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void say() {
        System.out.println("UserDaoImpl start...");
    }
}

使用的bean不是同一个 

测试效果:

 地址不同,不是同一个bean对象

 bean的生命周期

自定义方法,在方法上添加@PostConstruct注解和@PreDestory注解

@Component("userService")
public class UserServiceImpl implements UserService {
    @Resource(name = "userDao")
    private UserDao userDao;
    @Override
    public void say() {
        userDao.say();
        System.out.println("UserServiceImpl....");

    }
    @PostConstruct
    public void  init(){
        System.out.println("执行初始化");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("执行销毁");
    }
}

测试效果:

 

只有初始化方法执行了,为什么销毁方法没有执行?

因为:JVM虚拟机执行完成后直接关闭,没有给Spring的IOC容器关闭的时机,导致销毁方法没有执行(销毁方法的时机在容器关闭时),因此需要手动设置关闭钩子或在代码执行前手动关闭Spring容器。

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {

        AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(SpringConfig.class);
        UserDao userDao = (UserDao) context.getBean("userDao");
        UserDao userDao1 = (UserDao) context.getBean("userDao");
        System.out.println(userDao);
        System.out.println(userDao1);
        context.close();
    }
}

注意:  

  • close():方法属于AnnotationConfigApplicationContext和ClassPathXmlApplicationContext实现类,ApplicationContext接口中是不存在这个方法的,因此不是使用接口接收实现类的方式调用该方法。
  • close():是强制关闭IOC容器,因此必须放在要执行的代码的最后位置,因为该方法的下方不能执行任何代码
  • 除了使用close()方法关闭容器的方式外,还可以设置关闭钩子方法,它会监听JVM虚拟机的关闭的时机,自动在JVM关闭前关闭IOC容器,它的位置可以是任意的
public class App 
{
    public static void main( String[] args )
    {

        AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(SpringConfig.class);
        UserDao userDao = (UserDao) context.getBean("userDao");
        UserDao userDao1 = (UserDao) context.getBean("userDao");
        context.registerShutdownHook();
        System.out.println(userDao);
        System.out.println(userDao1);
   
    }
}

测试效果:close()和registerShutdownHook() 的效果是一样的 

 额外注意

@PostConstruct和@PreDestroy注解位于java.xml.ws.annotation包,该包是Java EE的模块一部分。J2EE已经在Java 9中被弃用,并且计划在Java 11中删除它。我使用的JDK1.8,如果大家使用的是JDK11或17以及更高版本,可能无法使用这两个注解。

解决方案:为pom.xml添加额外的依赖

    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>

依赖注入

自动装配

spring注解开发,是为了加速开发,所以对原始的功能进行了阉割,如setter注入。现在使用自动装配的形式完成依赖注入

可以理解为:原先我们需要现在spring的配置文件中声明bean和bean之间的依赖关系;并且需要在要注入对象的实体类中声明set方法。现在使用注解,只需要使用@Component注解声明bean被IOC容器管理,并且使用@Autowired来注入实体类需要的对象,就可以完全替代在spring.xml的配置文件中进行一系列操作。

 创建一个Service类,需要注入Dao类

UserService

public interface UserService {
    public void  say();
}

UserServiceImpl

@Component("userService")
public class UserServiceImpl implements UserService {
     @Autowired
    private UserDao userDao;
    @Override
    public void say() {
        userDao.say();
        System.out.println("UserServiceImpl....");

    }
    @PostConstruct
    public void  init(){
        System.out.println("执行初始化");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("执行销毁");
    }
}

APP

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {

        AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService =(UserService) context.getBean("userService");
        userService.say();
        context.close();

    }
}

测试效果:

  • 本质上:取代了set方法,底层使用了暴力反射机制,强制给属性注入值。
  • 如果类型不唯一,可以按照名称进行注入。

@Component("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    @Qualifier(value = "userDao")
    private UserDao userDao;
    @Override
    public void say() {
        userDao.say();
        System.out.println("UserServiceImpl....");

    }
    @PostConstruct
    public void  init(){
        System.out.println("执行初始化");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("执行销毁");
    }
}
  • 使用@Qualifier注解必须依赖Autowired注解,因此不能删除
  • 可以使用@Resource注解,也是按照名称进行依赖注入,但要区分两者之间的区别

@Component("userService")
public class UserServiceImpl implements UserService {

    @Resource(name = "userDao")
    private UserDao userDao;
    @Override
    public void say() {
        userDao.say();
        System.out.println("UserServiceImpl....");

    }
    @PostConstruct
    public void  init(){
        System.out.println("执行初始化");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("执行销毁");
    }
}
  • @Qualifier(value = "userDao"):是Spring提供的注解
  • @Resource(name = "userDao"):是JDK提供的注解

 简单类型注入

 使用@Value注解进行依赖注入

@Component("userService")
public class UserServiceImpl implements UserService {

    @Resource(name = "userDao")
    private UserDao userDao;
    @Value("Hello World")
    private String hello;
    @Override
    public void say() {
        userDao.say();
        System.out.println("UserServiceImpl....");
        System.out.println(hello);

    }
    @PostConstruct
    public void  init(){
        System.out.println("执行初始化");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("执行销毁");
    }
}

  • 简单类型的注入可以通过动态加载properties文件进行
  • 通过配置的形式加载properties文件

 

配置文件中要注意空格,因为空格也算作一个数据

@Component("userService")
@PropertySource("jdbc.properties")
public class UserServiceImpl implements UserService {

    @Resource(name = "userDao")
    private UserDao userDao;
    @Value("${ceshi}")
    private String hello;
    @Override
    public void say() {
        userDao.say();
        System.out.println("UserServiceImpl....");
        System.out.println(hello);

    }
    @PostConstruct
    public void  init(){
        System.out.println("执行初始化");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("执行销毁");
    }
}
  • @PropertySource("jdbc.properties")
    • 指定配置文件的位置,默认查找classpath路径
  • @Value注解中使用${}引入配置文件重点键值对数据
    • ${键名}

 第三方bean的管理

  • 因为引入第三方的bean,因为不能将配置写在其源代码中,因此只能编程的方式去获取。
  • 定义的方法名建议取成你想管理的bean的id名称

 接下来已管理第三方的数据源为例,演示如何使用注解的方式管理一个第三方的bean

第一步:导入数据源的依赖

我使用的是阿里巴巴的德鲁伊(druid)数据源,也可以换成其他的数据源,只是配置方式略有不同

  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.16</version>
    </dependency>

 第二步:在配置类中声明第三方bean

@Configuration
@ComponentScan("org.example")
public class SpringConfig {

    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/ssm_vue_demo");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}
  • 定义一个第三方bean一般按照类型进行使用,使用名称的机会不大。
  • 获取第三方bean :就是在配置类中使用Bean注解定义一个方法,方法的返回值就是要获取的bean对象。

 测试效果:

public class App 
{
    public static void main( String[] args )
    {

        AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext(SpringConfig.class);
        DataSource dataSource = context.getBean(DataSource.class);
        System.out.println(dataSource);

    }
}

 数据源和连接信息分离

需要进一步简化spring配置,因为数据库连接池信息属于jdbc配置,直接写在spring的配置中不规范,可以拆分出去

使用独立的配置类管理第三方bean

@Configuration
public class JdbcConfig {
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/ssm_vue_demo");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

 两种方式

方式1:

  • 将独立的配置类加入核心配置
  • 扫描式
@Configuration
//使用Component注解扫描配置类所在的包,加载对应的配置类信息,我这里扫描了全包,所有可以扫描到@Configuration注解
@ComponentScan("org.example")
public class SpringConfig {


}

这种方式不推荐,因为配置类过多时,容器产生错误观察

方式2:

  • 将独立配置类加入核心配置
  • 导入式 
@Configuration
//使用@Import注解手动加入配置类到核心配置,此注解只能添加一次,多个数据请用数组格式
@Import(JdbcConfig.class)
public class SpringConfig {


}

 为第三方bean注入资源

  • 简单类型注入:使用@Value注解
  • 引用类型注入:只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象

注解开发总结

功能XML配置注解
定义bean

bean标签

  • id属性
  • class属性

@Component

  • @Controller
  • @Service
  • @Repository

@ComponentScan

设置依赖注入

setter注入(set方法)

  • 引用/简单

构造器注入(构造方法)

  • 引用/简单

自动装配

@Autowired

  • @Qualifier

@Value

配置第三方bean

bean标签

静态工厂、实例工厂、FactoryBean

@Bean
作用范围scope属性@Scope
生命周期

标准接口

  • init-method
  • destroy-method

@PostConstrutor

@PreDestroy

标签:userDao,Spring,void,bean,开发,println,注解,public
From: https://blog.csdn.net/weixin_52937170/article/details/143039184

相关文章

  • springboot+vue保险业务管理系统【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着经济的快速发展和人民生活水平的显著提升,保险作为一种风险管理的重要手段,在保障个人与企业财产安全、缓解经济压力方面发挥着日益重要的作用。近年来,保险行业呈现出快速增长的态势,业务量激增,客户群体日益多元化,这对保险公司的业务......
  • springboot+vue保密知识学习APP 后8【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着信息化时代的到来,保密工作面临着前所未有的挑战。信息的快速传播和技术的不断发展,使得保密知识的普及和更新变得尤为重要。然而,传统的保密知识学习方式存在诸多局限性,如资源有限、形式单一、更新不及时等问题,难以满足广大用户对保......
  • springboot+vue保洁预约系统【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景在当今社会,随着生活节奏的加快和工作压力的增大,人们越来越注重家居环境的整洁与舒适。然而,传统的保洁服务往往存在预约不便、服务标准不统一、信息不透明等问题,难以满足现代家庭对高效、便捷、个性化保洁服务的需求。随着移动互联网技......
  • springboot+vue保费征缴管理模块设计与实现【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着社会经济的快速发展和人民生活水平的不断提高,保险已成为现代社会中不可或缺的风险管理工具。保费征缴作为保险业务中的关键环节,直接关系到保险公司的运营效率和参保人的权益保障。然而,传统的保费征缴方式往往存在流程繁琐、信息不......
  • 基于java+springboot的智慧博物馆预约平台
    文章目录前言项目介绍技术介绍功能介绍核心代码数据库参考系统效果图前言文章底部名片,获取项目的完整演示视频,免费解答技术疑问项目介绍  伴随着我国社会的发展,人民生活质量日益提高。于是对智慧博物馆预约管理进行规范而严格是十分有必要的,所以许许多多的信息......
  • Meta 最新 SPIRIT-LM:语音文本无缝转换还能懂情绪;字节回应实习生破坏大模型训练:网传损
        开发者朋友们大家好: 这里是「RTE开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享RTE(Real-TimeEngagement)领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表......
  • springboot+vue宝成社区志愿者服务管理系统【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着社会经济的快速发展和人民生活水平的不断提高,社区作为城市的基本单元,其治理水平和服务质量日益成为衡量城市文明程度的重要标志。宝成社区作为众多社区中的一员,面临着居民需求多样化、社区事务繁杂化的挑战。为了有效提升社区服务......
  • 开发-Hadoop-配置Hadoop
    最终效果   首先你得有一个Centos7的环境我直接用VirtualBox虚拟了一个Centos7(mini包)   #连接ssh#替换yum库curl-o/etc/yum.repos.d/CentOS-Base.repohttp://mirrors.aliyun.com/repo/Centos-7.repoyummakecache#升级renguanyuvim/etc/sudoers#如果是......
  • Vue3 + TypeScript:从环境搭建到组件通信的完整前端开发教程
    在前端开发领域,Vue3与TypeScript的组合备受青睐。Vue3带来高效灵活的开发体验,TypeScript则提供强大的类型安全和可维护性。本文将详细介绍如何使用Vue3和TypeScript进行开发,文章内容将按照以下顺序展开:一、环境准备1.安装Node.js:从Node.js官方网站下载并安装适合......
  • 【OpenAI】第一节(OpenAI API)获取OpenAI API KEY的两种方式,开发者必看全方面教程!
    在当今人工智能迅猛发展的时代,OpenAI的大模型为开发者提供了强大的文本生成能力。无论你是想创建聊天机器人、内容生成工具,还是其他创新应用,掌握如何获取和使用OpenAIAPIKey是你迈向成功的第一步!本文将详细介绍获取APIKey的步骤、充值方法以及如何在项目中调用API......