基于注解以及配置类使用SpringIoc

四 基于注解方式使用SpringIoc

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

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

4.1 组件(Bean)的注册

思路: 使用注解标记组件,让spring框架识别注解并管理组件。

由于效率原因,spring框架并不会扫描所有的包,去寻找注解,这样效率很低。所以需要我们去告知spring,我们在那些包内使用了注解或者想要springioc管理的组件。

所以组件的注册分为两步: 1.添加注解,2.告知spring添加注解的包,即包扫描

ps:在使用第三方类的时候,如JdbcTemplate类,就无法使用注解去注册,还是要使用xml方式配置

4.1.1添加注解

Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。

注解说明
@Component 该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。
@Repository 该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Service 该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
@Controller 该注解通常作用在控制层(如SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

四个注解对于Spring使用IOC容器管理这些组件来说没有区别,也就是语法层面没有区别。所以@Controller、@Service、@Repository这三个注解只是给开发人员看的,让我们能够便于分辨组件的作用。

与xml注册bean,相比较:

@Component
public class CommonComponent {
}
//还需要告诉spring,在哪里使用了注解
<bean  id="commonComponent" class="com.ls.pojo.CommonComponent"/>

相比较注解不用强制写id值,有默认id值类名首字母小写,当然也可以自定义id值。value=“xxx”

4.1.2包扫描

情况1:基本扫描配置

<?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 https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 配置自动扫描的包 -->
    <!-- 1.包要精准,提高性能!
         2.会扫描指定的包和子包内容
         3.多个包可以使用 base-package="包1,包2,包3"
    -->
    <context:component-scan base-package="com.ls.components"/>
  
</beans>

情况2:扫描目标包中排除组件

<!-- 情况三:指定不扫描的组件 -->
<context:component-scan base-package="com.ls.components">
    
    <!-- context:exclude-filter标签:指定排除规则 -->
    <!-- type属性:指定根据什么来进行排除,annotation取值表示根据注解来排除 -->
    <!-- expression属性:指定排除规则的表达式,对于注解来说指定全类名即可 -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

情况3:扫描目标包指定扫描组件

<!-- 情况四:仅扫描指定的组件 -->
<!-- 仅扫描 = 关闭默认规则 + 追加规则 -->
<!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
<context:component-scan base-package="com.ls.ioc.components" use-default-filters="false">
    
    <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

之所以包扫描有下面两种方式是因为避免重复扫描,创建重复创建组件造成的资源浪费。

在后面的三成架构中,室友两个容器 webioc容器,rootioc容器。webioc容器用来存放controller组件,root容器存放初了controller组件的其他所有组件。

4.2 周期性方法和作用域

使用 @PostConstruc @PreDestroy注解需要导入javax-annotation-api

@Component
public class Person {


    //周期方法必须 public void 修饰,并且无参
	//导入依赖javax.annotation-api,才能使用这个注解
    @PostConstruct //注解指定bean的初始化方法
    public  void  one(){
        System.out.println("起床~~~~");
    }

    @PreDestroy//注解指定bean的销毁方法
    public void end(){
        System.out.println("睡觉~~~~~");
    }

}

作用域:

@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) //单例,默认值
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //多例  二选一
public class BeanOne {

  //周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
  @PostConstruct  //注解制指定初始化方法
  public void init() {
    // 初始化逻辑
  }
}

4.3Bean的依赖注入

4.3.1@Autowired 引用类型注入

**注解@Autowired **

在成员变量上直接标记@Autowired注解即可,不需要提供setXxx()方法。前提参与自动装配的组件(需要装配、被装配)全部都必须在IoC容器中。

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    public void show(){
        userDao.call();
    }
}

这里存在的问题:

参考博客:Field injection is not recommended(Spring团队不推荐使用Field注入)-CSDN博客

注解不仅仅可以放在类上,也可以放在setter方法,和构造器上,对应着xml方式setter方法注入,和构造器注入

@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    //setter方法注入
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    //构造器注入
    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public void show(){
        userDao.call();
    }
}
  1. @Autowired注解细节

    1. 标记位置

      1. 成员变量

这是最主要的使用方式!

与xml进行bean ref引用不同,他不需要有set方法!

  1. 工作流程

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

  • 能够找到唯一的 bean:直接执行装配

  • 如果完全找不到匹配这个类型的 bean:装配失败

  • 和所需类型匹配的 bean 不止一个

  • 没有 @Qualifier 注解:根据 @Autowired 标记位置成员变量的变量名作为 bean 的 id 进行匹配

  • 能够找到:执行装配

  • 找不到:装配失败

  • 使用 @Qualifier 注解:根据 @Qualifier 注解中指定的名称作为 bean 的id进行匹配

  • 能够找到:执行装配

  • 找不到:装配失败

4.3.2扩展JSR-250注解@Resource

  1. **扩展JSR-250注解@Resource **
  • 理解JSR系列注解

JSR(Java Specification Requests)是Java平台标准化进程中的一种技术规范,而JSR注解是其中一部分重要的内容。按照JSR的分类以及注解语义的不同,可以将JSR注解分为不同的系列,主要有以下几个系列:

  1. JSR-175: 这个JSR是Java SE 5引入的,是Java注解最早的规范化版本,Java SE 5后的版本中都包含该JSR中定义的注解。主要包括以下几种标准注解:
  - `@Deprecated`: 标识一个程序元素(如类、方法或字段)已过时,并且在将来的版本中可能会被删除。
  - `@Override`: 标识一个方法重写了父类中的方法。
  - `@SuppressWarnings`: 抑制编译时产生的警告消息。
  - `@SafeVarargs`: 标识一个有安全性警告的可变参数方法。
  - `@FunctionalInterface`: 标识一个接口只有一个抽象方法,可以作为lambda表达式的目标。
  1. JSR-250: 这个JSR主要用于在Java EE 5中定义一些支持注解。该JSR主要定义了一些用于进行对象管理的注解,包括:
  - `@Resource`: 标识一个需要注入的资源,是实现Java EE组件之间依赖关系的一种方式。
  - `@PostConstruct`: 标识一个方法作为初始化方法。
  - `@PreDestroy`: 标识一个方法作为销毁方法。
  - `@Resource.AuthenticationType`: 标识注入的资源的身份验证类型。
  - `@Resource.AuthenticationType`: 标识注入的资源的默认名称。
  1. JSR-269: 这个JSR主要是Java SE 6中引入的一种支持编译时元数据处理的框架,即使用注解来处理Java源文件。该JSR定义了一些可以用注解标记的注解处理器,用于生成一些元数据,常用的注解有:
  - `@SupportedAnnotationTypes`: 标识注解处理器所处理的注解类型。
  - `@SupportedSourceVersion`: 标识注解处理器支持的Java源码版本。
  1. JSR-330: 该JSR主要为Java应用程序定义了一个依赖注入的标准,即Java依赖注入标准(javax.inject)。在此规范中定义了多种注解,包括:
  - `@Named`: 标识一个被依赖注入的组件的名称。
  - `@Inject`: 标识一个需要被注入的依赖组件。
  - `@Singleton`: 标识一个组件的生命周期只有一个唯一的实例。
  1. JSR-250: 这个JSR主要是Java EE 5中定义一些支持注解。该JSR包含了一些支持注解,可以用于对Java EE组件进行管理,包括:
  - `@RolesAllowed`: 标识授权角色
  - `@PermitAll`: 标识一个活动无需进行身份验证。
  - `@DenyAll`: 标识不提供针对该方法的访问控制。
  • @DeclareRoles: 声明安全角色。

但是你要理解JSR是Java提供的技术规范,也就是说,他只是规定了注解和注解的含义,JSR并不是直接提供特定的实现,而是提供标准和指导方针,由第三方框架(Spring)和库来实现和提供对应的功能。

  • JSR-250 @Resource注解

@Resource注解也可以完成属性注入。那它和@Autowired注解有什么区别?

  - @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
  - @Autowired注解是Spring框架自己的。
  - **@Resource注解默认根据Bean名称装配,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型装配。**
  - **@Autowired注解默认根据类型装配,如果想根据名称装配,需要配合@Qualifier注解一起用。**
  - @Resource注解用在属性上、setter方法上。
  • @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

@Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖:【高于JDK11或低于JDK8需要引入以下依赖

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>
- @Resource使用
@Controller
public class XxxController {
    /**
     * 1. 如果没有指定name,先根据属性名查找IoC中组件xxxService
     * 2. 如果没有指定name,并且属性名没有对应的组件,会根据属性类型查找
     * 3. 可以指定name名称查找!  @Resource(name='test') == @Autowired + @Qualifier(value='test')
     */
    @Resource
    private XxxService xxxService;

    //@Resource(name = "指定beanName")
    //private XxxService xxxService;

    public void show(){
        System.out.println("XxxController.show");
        xxxService.show();
    }
}

4.3.3 基本属性赋值

@Value 通常用于注入外部化属性,正常情况下就直接==赋值

声明外部配置

application.properties

catalog.name=MovieCatalog

xml引入外部配置

<!-- 引入外部配置文件-->
<context:property-placeholder location="application.properties" />

@Value注解读取配置

package com.atguigu.components;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * projectName: com.atguigu.components
 *
 * description: 普通的组件
 */
@Component
public class CommonComponent {

    /**
     * 情况1: ${key} 取外部配置key对应的值!
     * 情况2: ${key:defaultValue} 没有key,可以给与默认值
     */
    @Value("${catalog:hahaha}")
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

4.4总结

使用注解开发使用ioc,并不能完全摒弃xml配置,还需要使用xml配置

  • 扫包,注解使用的范围
  • 引入外部文件
  • 第三方提供的类,还需要在xml配置,如druid,jdbctemplate

五 使用配置类以及注解方式使用ioc

5.1 什么是配置类,以及使用

什么是配置类,就是将配置文件,改成配置类。

在上述使用注解的过程中,发现仍需要使用xml配置文件,xml配置文件的需要做的事情是:

  • 扫包   component-scan base-package=“xxx”
  • 引入外部文件   property-placeholder location=“xxxx”
  • 注册第三方提供的类

由于xml解析的效率较低,使用一个类实现以上功能,我们在此称这个类为配置类。

/**
 * 配置类代替xml文件
 * 1. 引入外部文件
 * 2. 扫包
 * 3. 注册第三方的类
 */
@Configuration
@ComponentScan({"com.ls.dao","com.ls.service"})
@PropertySource("classpath:jdbc.properties")
public class MainConfiguration {

    //注册数据源---->使用druid第三方提供的类
    @Bean
    public DataSource dataSource(@Value("${jdbc.url}") String url,
                                      @Value("${jdbc.driver}") String driverClassname,
                                      @Value("${jdbc.username}") String username,
                                      @Value("${jdbc.password}") String password){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driverClassname);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return  druidDataSource;
    }
}

获得用配置类创建的ioc容器的时候是使用另一实现类AnnotationConfigApplicationcontext.

5.2@Bean的详细使用

  • bean的详细使用 name,initMethod,destroyMethod,以及作用域Scope(“singleton"or"prototype”)
  • bean之间的依赖
@Configuration
@ComponentScan({"com.ls.dao","com.ls.service"})
@PropertySource("classpath:jdbc.properties")
public class MainConfiguration {
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.driver}")
    private String driverClassname;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;


    //注册数据源---->使用druid第三方提供的类
    @Bean
    public DataSource dataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driverClassname);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);

        return  druidDataSource;
    }
    //bean的详细使用 name,initMethod,destroyMethod,以及作用域Scope("singleton"or"prototype")
    /**bean之间的依赖  ------->jdbcTemplate--->datasource
     * 方式一: 如果需要注入的依赖,也是@Bean标签下的,可以直接使用方法引用
     * 方式二: 使用参数注入,就是将需要注入的依赖,以参数的形式传入被注入的bean。
     *          确保参数一定存在参数类型的bean
     *          如果有多个类型,可以直接使用需要注入的名
     */

    @Bean(name = "jdbcTemplate", initMethod = "",destroyMethod = "")
    @Scope("singleton")
    public JdbcTemplate jdbcTemplate(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //如果需要注入的依赖,也是@Bean标签下的,可以直接使用方法引用
        jdbcTemplate.setDataSource(dataSource());
        return jdbcTemplate;
    }

    //使用参数传值,就是将需要注入的依赖,以参数的形式传入被注入的bean。
    @Bean
    public JdbcTemplate jdbcTemplate1(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource());
        return jdbcTemplate;
    }
}

5.3 @Import使用

@Import 注释允许从另一个配置类加载 @Bean 定义,如以下示例所示:

@Configuration
public class ConfigA {

  @Bean
  public A a() {
    return new A();
  }
}

@Configuration
@Import(ConfigA.class)
public class ConfigB {

  @Bean
  public B b() {
    return new B();
  }
}

@Import的使用是作用在注解类上的,目的就是整合注解类,减少创建ioc时的参数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值