首页 > 其他分享 >spring基础之常用组件

spring基础之常用组件

时间:2023-06-28 12:22:35浏览次数:42  
标签:容器 常用 person spring class Person bean 组件 public

spring基础之常用组件

一、基于xml注入bean

先看看我们在没有使用注解之前,最早使用xml进行bean的注入是怎么操作的呢?

首先我们需要在项目中创建一个.xml文件然后使用bean标签注册一些组件。现在我们就以注册person这个bean进行举例。

先创建一个需要注册的bean实例

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;

}

然后再resource下面创建一个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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="person" class="com.spring.assembly.bean.Person">
        <property name="name" value="让你三行代码"/>
        <property name="age" value="18"/>
    </bean>

</beans>

新建一个测试类来测试一下

    @Test
    public void test01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Person person = (Person) context.getBean("person");
        //打印结果
        System.out.println(person);
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

通过测试打印的结果我们可以看到已经打印了我们再xml文件中配置bean的数据。我们先来解读一下,ClassPathXmlApplicationContext,这个是什么意思了?其实就是通过ClassPathXmlApplicationContext把我们类路径下的spring的配置文件加载到容器中,在spring容器中,给我提供了很多方法,其中有个getBean()的方法,这个方法就是通过name去获取容器中已经注册的bean对象,这个name是什么呢?其实就是我们在xml中的那个bean id。如果这两个不一致就在容器中找不到这个bean.
在这里插入图片描述

二、基于注解注入bean

上面我们讲完了基于xml的方式注入bean,下面我们接着通过注解的方式注入bean,为什么有了基于xml的方式还要有基于注解的方式呢?主要是基于xml的方式过于繁琐,配置文件多,而基于注解的方式我们只需要一个注解就搞定了,既方便又轻松。

我们基于注解的方式很显然是不需要写xml文件的,下面我们就来实现一个基于注解的方式。

首先我们先创建一个AnnotateConfi类,给这个类上加上@Configuration这个注解,这个注解是什么意思呢?这个注解就是代表是配置类等价于我们的配置文件。 @Bean这个注解是什么意思呢?就是说我们现在给容器中注册一个bean,类型为返回值的类型。

@Configuration
public class AnnotateConfig {

    @Bean
    public Person person(){
        System.out.println("给容器中注册person");
        return new Person("让你三行代码",20);
    	}
    }

下面我们测试一下,我们的容器中有没有这个bean

@Test
    public void test02(){

        ApplicationContext app = new AnnotationConfigApplicationContext(AnnotateConfig.class);
        //在容器中获取对象
        Person person = (Person) app.getBean("person");
        //打印结果
        System.out.println(person);

        //获取person这个对象的bean id
        String[] names = app.getBeanNamesForType(Person.class);

        for (String name : names) {
            System.out.println(name);
            //peron 这里我们没有命名,但是自动给我们取了一个id叫person,对于@Bean这个注解来说就是用的这个方法的名字作为id来使用的,

            /**
             * IOC容器会初始化很多javaBean实例,他们是怎么存放的呢?其实就是一个Map对象,map.put("key","value")
             * 这个key就是我们的id  value就是我们javabean的实例,就是和我们配置相关的这个id
             * 我们要修改这个bean实例的id,直接在@Bean注解中加入就可以了*/
        }
    }

在这里插入图片描述
结果很显然我们也是容容器中拿到了这个bean,具体是怎么注册的呢?其实就是通过AnnotationConfigApplicationContext这个容器类把我们的配置文件加载到容器中。然后在通过容器中提供的getBean的方法获取bean对象。

AnnotationConfigApplicationContext这个容器类是一个非常重要的容器类,所有的bean的创建,bean的实例化,bean的前置后置都是在这里类中进行的,这是一个核心类

对于xml文件配置我们给需要注册的bean设置了id,那么我们通过注解方式注册的bean的id是什么呢?其实容器也给我们提供了一个方法,这个方法getBeanNamesForType就可以获取出来我们通过注解注册的bean的id.

   @Test
    public void test02(){

        ApplicationContext app = new AnnotationConfigApplicationContext(AnnotateConfig.class);
        //在容器中获取对象
        Person person = (Person) app.getBean("person");
        //打印结果
        System.out.println(person);
        String[] names = app.getBeanNamesForType(Person.class);
        for (String name : names) {
            System.out.println(name);
        }
    }

在这里插入图片描述
通过运行上面的代码我们可以发现我们没有命名但是自动给我们取了一个id叫person,其实对于注解@bean来说,它就是我们的这个方法的名字 (public Person person(){})作为id来使用的。那通过注解的方式来注册bean的id都是这个方法的方法名,那是不是这个id就不能修改呢?这个显然是不对,想要修改bean其实很简单只需要在我们注解@bean后面加上我们自己要修改的bean的id就可以了。

@Configuration
public class AnnotateConfig {

    @Bean("person2")
    public Person person(){
        System.out.println("给容器中注册person");
        return new Person("让你三行代码",20);
    }

在这里插入图片描述

容器会初始化很多javaBean,他们到底是怎么存放的呢?其实就是一个很大的map对象,这个map的key就是我们注册bean的id,value就是我们bean的实例。

三、ComponentScan扫描规则

自定义包扫描

ComponentScan这个注解的作用其实就是可以扫描指定路径下的所有的组件

下面我们就来测试一下,先创建一个配置文件给它加上注解指定让它去扫描com.spring.assembly.componentScan这个包下的组件

@Configuration
@ComponentScan(value = "com.spring.assembly.componentScan")
public class ScanConfig {

    @Bean
    public Person person(){
        return new Person("让你三行代码",20);
    }
}

然后我们在这个com.spring.assembly.componentScan包下面去创建几个类,然后我们去获取到容器中的bean,看我们能不能获取到

@Controller
public class PersonController {
}

@Service
public class PersonService {
}
@Repository
public class PersonDao {
}
  @Test
    public void test03(){
        ApplicationContext context = new AnnotationConfigApplicationContext(ScanConfig.class);
        System.out.println("ioc容器创建完成");

        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
    }

在这里插入图片描述

通过结果我们可以看出@ComponentScan这个注解根据我们的配置的包路径已经扫描到了相对应的组件。

自定义包扫描规则

@ComponentScan这个注解不仅仅是可以自定义包路径扫描,它还可以做到自定义包扫描规则,什么叫自定义包扫描规则呢?通俗一点讲就是我们自定这个包路径下那些组件扫描,那些不扫描。

那现在我们去定义@ComponentScan这个注解扫描com.spring.assembly.componentScan这个包下面的@controller这个注解,@service和@Repository这两个注解不进行扫描。我们只需要在@ComponentScan这个注解里面进行配置就行了

@Configuration
@ComponentScan(value = "com.spring.assembly.componentScan",
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes ={Controller.class})},
        useDefaultFilters = false)
public class ScanConfig {

    @Bean
    public Person person(){
        return new Person("让你三行代码",20);
    }
}

在这里插入图片描述

从结果可以看出,我加上了 includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes ={Controller.class})}, useDefaultFilters = false这么一段之后我们的@service和@Repository这两个注解在我们的容器中是没有注册的。为什么加上这段话就不会进行注册呢?includeFilters 的意思就是指定那些组件应该被包含进来(excludeFilters指定按照什么规则排除组件),这个注解是一个数组,每一个元素就是一个Filter对象,这个Filter就是这些组件扫描过滤的类,从源码不难看出,扫描的规则有下面下面5中,ANNOTATION是按照注解,ASSIGNABLE_TYPE是按照给定的类型,ASPECTJ是使用ASPECTJ表达式,REGEX是使用正则表达式,CUSTOM使用自定义规则,自己写类实现TypeFilter接口**。

在这里插入图片描述

useDefaultFilters表示是否启用默认的组件扫描规则,设置false表示不启用默认的过滤规则,用户需要自定义过滤规则,如果设置为true的话,spring会默认扫描符合标准的类。这里有一个坑,就是如果使用了自定义的过滤器的话,我们设置成true会怎么样呢?下面我们就来测试一下

@Configuration
@ComponentScan(value = "com.spring.assembly.componentScan",
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes ={Controller.class})},
        useDefaultFilters = true)
public class ScanConfig {

    @Bean
    public Person person(){
        return new Person("让你三行代码",20);
    }
}

在这里插入图片描述

我们从结果可以看出,如果我们使用自定义过滤规则,useDefaultFilters设置为true,我们自定义的过滤规则就会失效。为什么设置成true就不会生效了?跟进去源码当我们设置useDefaultFilters为true时就进入registerDefaultFilters这个方法,这个方法里面就会执行this.includeFilters.add(new AnnotationTypeFilter(Component.class));这个语句,执行这个语句就是会把所有以注解@Component开头的都会扫描进来。所以当我们设置为true的时候personService和sersonDao这两个bean为什么也会注册进来了,其实@service和@repository顶层也是@component,相当于实现了@component的接口。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

四、scope扫描规则

@scope的作用是用于管理spring容器中bean的作用域范围的。

@Scope的取值一般常用的就是singletonprototype这两种,singleton(默认值)表示spring容器中会为这个bean创建单个bean,在整个容器中共享prototype表示每次从容器中获取bean的时候都会重新创建一个新的bean。

下面是将bean设置为singleton

@Configuration
public class AnnotateConfig {

    @Scope("singleton")
    @Bean
    public Person person(){
        System.out.println("给容器中注册person");
        return new Person("让你三行代码",20);
    }

    @Test
    public void test03(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AnnotateConfig.class);
        System.out.println("ioc容器创建完成");
        Person person =(Person) context.getBean("person");
        Person person1 =(Person) context.getBean("person");
        System.out.println(person==person1);
    }

在这里插入图片描述

当我设置为singleton的时候从容器中获取两次bean进行比较他们都是同一个对象。

下面是将bean设置为prototype

@Configuration
public class AnnotateConfig {

    @Scope("prototype")
    @Bean
    public Person person(){
        System.out.println("给容器中注册person");
        return new Person("让你三行代码",20);
    }

在这里插入图片描述

通过结果我们可以看出bean设置为prototype的时候是获取的不同的对象。

五、懒加载@Lazy

什么是懒加载呢?其实就是在我们需要的时候才会去注册我们需要的bean实例,懒加载主要针对的时候单实例bean。下面我们就用代码演示一下。

@Configuration
public class AnnotateConfig {
    @Lazy
    @Bean
    public Person person(){
        System.out.println("给容器中注册person");
        return new Person("让你三行代码",20);
    }

    @Test
    public void test03(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AnnotateConfig.class);
        System.out.println("容器创建完成");
    }

在这里插入图片描述

通过结果可以看出来我们的person是没有注册到容器中的。下面我们在演示一下容器创建完之后我们去获取我们的bean.

  @Test
    public void test03(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AnnotateConfig.class);
        System.out.println("容器创建完成");
        context.getBean(Person.class);
    }

在这里插入图片描述

可以看出我们的bean已经注册到了容器中,也就是说当我们使用了@Lazy这个注解的时候,容器初始化的时候并不会给我们注册bean,只有我们在第一次时间的时候才会加载到IOC容器中去。

六、@Conditional条件注册bean

@Conditional其实就是根据条件来决定时候去创建这个bean

下面我们定义两个对象person和person2,判断我们当前环境如果是windows我们就不注册person2这个bean.

首先我们定义一个WinCondition这个类,这个类主要是去作为条件去判断,这个类需要去实现spring的Confition接口,重写它的matches方法,这个方法中ConditionContext这个参数就是判断条件可以使用的上下文环境,AnnotatedTypeMetadata这个参数可以获取注解的信息。

public class WinCondition implements Condition {
    /**
     *
     * @param context 判断条件可以使用的上下文环境
     * @param metadata 注解的信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //获取到IOC容器中正在使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //获取当前环境变量
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        System.out.println(property);
        if(property.contains("Windows")){
         return false;
        }
        return true;
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private Integer age;

}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person2 {

    private String name;

    private Integer age;

}
@Configuration
public class AnnotateConfig5 {


    @Bean
    public Person person(){
        System.out.println("给容器中注册person");
        return new Person("让你三行代码",20);
    }

    @Conditional(WinCondition.class)
    @Bean
    public Person person2(){
        System.out.println("给容器中注册person2");
        return new Person("让你三行代码",30);
    }

}
 
@Test
    public void test04(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AnnotateConfig5.class);
        System.out.println("ioc容器创建完成");
    }

在这里插入图片描述

从结果不难看出我们并没有打印我们的person2,因为我们限制了,如果判断我们的系统是windows的话person2就不会注册。

标签:容器,常用,person,spring,class,Person,bean,组件,public
From: https://www.cnblogs.com/javayhy/p/17511079.html

相关文章

  • 【一】Docker常用命令
    【一】Docker常用命令1.查看容器名dockerps-a2.重启青龙容器dockerrestart你的容器名3.更新青龙(或者直接面板更新)dockerexec-itqinglongqlupdate4.更新青龙并编译dockerexec-itqinglongqlrestart5.拉取自定义仓库,已Faker仓库为例dockerexec-itqinglong......
  • VUE框架组件中通信方式(4)
    ref-children-parentref方法既可以获取真实的DOM节点,还可以获取到子组件的实例VC,$parent可以在子组件中获取父组件的实例VC,使用方式是在子组件的方法中传入的参数只能是$parent如:<button@click="handler($parent)">点击我爸爸给我10000元</button>示例代码如下;//父组件代码<......
  • JS中字符串28种常用API总结,substring、slice、JSON.stringify、match、split、search
    一、引言在前端开发中,处理字符串是一项常见的任务。JavaScript提供了一系列的字符串API,用于操作和处理字符串数据。字符串常用的API方法有很多,包括查找字符串、截取字符串、替换字符串、分割字符串、大小写转换、字符串拼接和字符串比较等等。本文将介绍一些常用的字符串API......
  • JS中数组22种常用API总结,slice、splice、map、reduce、shift、filter、indexOf......
    一、引言在前端开发中,数组是一种常见且重要的数据结构。数组提供了许多便捷的方法来操作和处理其中的数据。本文将简单介绍前端中数组常用的API,包括添加、删除、截取、合并、转换等操作。二、push()方法和pop()方法push()方法用于向数组末尾添加一个或多个元素,并返回修改......
  • kafka常用命令
    启动kafkabin/kafka-server-start.shconfig/server.properties、后台启动加参数-daemonbin/kafka-server-start.sh-daemon../config/server.properties查看topic信息cd到kafka的安装位置,找到bin目录  单机/集群都可以配置参数,下面命令为查询集群的topic信息bin/kafka-top......
  • 前端Vue自定义手机号文本格式化组件手机号码文本转星号
    前端Vue自定义手机号文本格式化组件,下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=13231效果图如下:cc-format-phone使用方法<!--phone:手机号isStar:是否转星号--><cc-format-phone:phone="":isStar="false"></cc-format-phone>......
  • DevExpress WPF Scheduler组件,快速构建性能优异的调度管理器!(上)
    无论您在WPF项目中是需要Outlook样式的调度程序,还是需要时间表或议程视图来向最终用户展示信息,DevExpressWPF Scheduler都提供了数十个选项,如集成的日程对话框等,因此用户可以快速构建下一个伟大的调度管理器。DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需......
  • playwright常用命令
    #安装pip3sudoaptinstallpython3-pip#安装pytest插件pip3installpytest-playwrightpip3installplaywright#安装chromiumfirefoxwebkit等浏览器的驱动文件(内置浏览器)python3-mplaywrightinstall若出现:BEWARE:yourOSisnotofficiallysupportedby......
  • Java之thread常用成员
    setName用于自定义线程的名字,方便我们调试定为问题;@TestpublicvoidsetNameTest(){Runnablerun=()->{System.out.println(Thread.currentThread().getName());};vart1=newThread(run);t1.start();......
  • SpringBoot接入Chat-GPT3
    创建一个APIKeyAPIKey创建网址:https://platform.openai.com/account/api-keys先登录OpenAI账号登陆后创建一个APIKey起一个名字点击创建,生成一个APIKey,记录下这个APIKey后续会用。可以在官网看到剩余容量,账号默认会送$18刀的容量,超过需要购买。在SpringB......