Spring基础篇:高级注解编程

news2025/2/24 11:03:55

文章内容来自于B站孙哥说Spring

  • 第一章:@Configuration
    • 一:配置Bean替换XML细节
    • 二:应用配置Bean工厂对象
    • 三:配置Bean细节分析
    • 1:整合Logback
    • 三:@Component
  • 第二章:@Bean
    • 一:@Bean的使用
    • 1:@Bean创建对象
      • 1):@Bean创建简单对象
      • 2):@Bean创建复杂对象
      • 3):@Bean创建复杂对象的注意事项
      • 4):@Bean注解自定义id值
      • 5):@Bean控制对象创建次数
    • 2:@Bean注入
      • 1):自定义类型注入
      • 2):JDK类型的注入
      • 3):JDK类型注入细节分析
  • 第三章:@ComponentScan
    • 一:@ComponentScan基本使用
    • 二:@ComponentScan排除策略
    • 三:@ComponentScan包含策略
  • 第四章:Spring工厂创建对象多种配置方式
    • 一:多种配置方式的应用场景
    • 二:多种配置方式优先级
    • 三: 解决注解配置的耦合问题
  • 第五章:整合多个配置信息
    • 一:为什么会有多个配置信息呢?
    • 二:如何将多个配置信息整合在一起
    • 1:整合要点
    • 2:多配置Bean的整合
    • 3:跨配置Bean进行注入
    • 4:配置Bean整合@Component
    • 5:配置Bean与配置文件的整合
      • 1):应用场景
      • 2):@ImportResource
    • 三:Bean的底层实现原理

Spring高级注解来自于Spring的3.x版本之后提供支持的,在Spring4 & 5当中提供了很好的应用和支持,通过这些注解的学习和研究可以是我们在后续的Spring开发当中基于纯注解方式来完成。

第一章:@Configuration

类上加了@Configuration注解他就算是配置Bean了

Spring3.x当中提供的高级注解,用于替换xml配置文件,引入了配置Bean就以为彻底放弃xml这种配置方式了,这也是我们将来学习SpringBoot开发过程中的核心。

学习这个配置Bean是非常简单的,我们创建一个类AppConfig当前这仅仅是一个很普通的Java类,我们加入完成@Configuration这个注解之后,这个类就变成了配置Bean就不再是普通的配置类了。

在应用配置Bean替换XML的过程中,有两个问题,如下:

一:配置Bean替换XML细节

实际上我们在xml配置文件当中通过核心配置文件,我们配置的这个配置Bean实际上他的作用就是用来替换核心配置文件的。

我们在核心配置文件当中配置过这个Bean标签的来创建Bean,并且在这个Bean标签当中对这个属性进行注入,注入自定义类型和JDK类型的属性。当然我们也可以在Spring核心配置文件当中配置包扫描,通过配置包扫描来配置扫描包下的包含注解的类来创建他们的对象,这些功能都是在核心配置文件当中完成的。

但是现在引入了这个配置Bean之后呢,所有的配置和操作都是在这个配置Bean当中完成,具体怎么完成,具体怎么完成将来会有更多的详细细节, 原有的XML当中的配置内容都可以通过这种配置Bean的方式进行解决。在这里插入图片描述

二:应用配置Bean工厂对象

应用配置Bean工厂对象也随之进行了改变。

我们来看一下在使用配置文件进行配置的时候,我们使用的工厂用的是,ClassPathXmlApplicationContext并且需要指定配置文件的位置。

对应的这个工厂对象已经不能够使用了,我们需要使用另一个对象,AnnotationConfigApplicationContext我们创建这个对象的同时也需要指定核心配置文件的位置,只不过指定的这个核心配置文件是一个Java类型的配置Bean的Class对象。

将配置Bean的这个类的Class对象作为参数传递进来,就可以依据这个核心配置文件创建Spring工厂对象,这个构造方法是由重载方法的,他的另一个参数是这个配置文件所在的包,可以指定这个配置参数所在的包,这样在这个包下或者子包下的配置文件就可以获取的到。这样的话,我们就可以根据这个配置文件创建你这个工厂对象的实例。

使用这个工厂对象的时候需要有两点注意事项:
1、创建工厂的代码,我们需要在创建工厂对象的过程当中使用这个工厂类变了
2、这个构造方法具有重载性。

三:配置Bean细节分析

在基于注解的开发过程中,我们想把所有的配置都配置到配置Bean当中,这时候对于日志配置来讲,这个时候我们是不能够集成Log4j的,甚至我们可以认为这个Log4J已经被淘汰了。

而在我们后续的开发过程中,Spring、甚至SpringBoot这样的话我们首推的是logback,下边呢,我们就看一下怎么继承这个logback呢?其实是非常简单,一个是引入Spring的jar包,一个是引入logback的核心配置文件。
将来我们使用Spring或者SpringBoot的时候都会使用这个logback的方式作为日志框架。

1:整合Logback

        <!--整合log4j日志框架kaishi-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.logback-extensions</groupId>
            <artifactId>logback-ext-spring</artifactId>
            <version>0.1.4</version>
        </dependency>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 控制台输出 -->
    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--格式化输出:%d表示⽇期,%thread表示线程名,
            %-5level:级别从左显示5个字符宽度%msg:⽇志消息,%n是换⾏符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}
                [%thread] %-5level %logger{50} - %msg%n
            </pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

三:@Component

加上这个注解之后就可以称为这个配置Bean,那么这个注解的本质是什么呢?这个也是@Component的衍生注解,点进去之后也有这个注解的上边有这@Component这个注解。

我们应用这个注解可以被标签进行扫描到,并创建对象,但是后续开发过程中我们没有人这么做,因为我们希望取代这个标签配置,彻底的放弃XML这种方式。

第二章:@Bean

我们通过配置Bean的方式替换了Spring的XML的核心配置文件,而作为xml的一个很重要的功能是配置Bean标签来配置Bean的创建。

然而我们当前如何在配置Bean当中完成标签Bean的配置呢,这就需要用到这个@Bean注解,这个就等同于xml当中的Bean标签

一:@Bean的使用

1:@Bean创建对象

1):@Bean创建简单对象

简单对象直接就是可以通过new的方式直接创建的对象

2):@Bean创建复杂对象

复杂对象就是Connection,SqlSessionFactory这样的对象,不能直接new的对象。

我们使用@Bean的前提就是使用配置Bean也就是说使用在@Configuration这样修饰的类中才能使用@Bean这个注解。我们添加一个@Bean注解,在对象的创建方法上,方法的返回值就是创建对象的类型。

@Bean注解修饰的方法名是有特殊的含义的,这个注解修饰的方法名就等同于,原来我们bean标签当中指定的id属性,这点需要额外注意。

方法体中的内容应该就是程序员想要创建对象的创建的过程。使用@Bean注解创建复杂对象也好,创建简单对象也好,直接将创建这个对象的方法写在@Bean修饰的方法的方法体中,这样的话,就完成了对象的创建,对象类型作为方法的返回体即可,然后方法名对应的就是具体的创建的Bean的id值,通过控制方法名的形式来控制创建出来的,程序员把对象创建的代码写在方法体中,这是Spring和程序员之间的协作
在这里插入图片描述
在这里插入图片描述
创建这个工厂的时候,我们可以传入配置Bean的class,也可以传入包的路径,Spring会扫描这个包查找包和子包下具有这个注解修饰的类型。

类似于接下来的复杂对象,我们是不能直接通过new的方式进行创建的,所以在Spring容器启动的时候,创建该对象的时候,需要Spring回调Spring的代码的书写,完成对象的创建,所以在Spring容器创建过程当中,我们可以看到一些复杂对象的创建的日志信息。比如连接对象,SQLSessionFactory这样的对象
在这里插入图片描述

3):@Bean创建复杂对象的注意事项

我们起初研究Spring的工厂的时候,我们创建复杂对象是将复杂对象实现一个Factory这样的一个接口来实现这样的功能,但是当我们现在基于配置Bean基于@Bean注解进行开发之后,我们使用@Bean这样完全没有问题,但是这样日后我们开发过程中,我们就使用了FactoryBean这种形式创建了复杂对象,这样是否可以和@Bean这种形式进行整合呢?

当然是可以的。只需要在配置Bean当中新提供一个@Bean注解,修饰一个新添加的方法,方法返回值为复杂对象,方法名为Bean的id,方法体中不需要进行创建对象的代码编写,只需要进行getObject方法的调用即可,这样就完成了Factory接口和二者的整合。

这个新的方法当中是写在配置类当中的,在这处理的过程当中,我们完成了将FactoryBean和@Bean的整合,也可以直接将复杂对象的创建写在配置类当中,仅仅使用这个@Bean的方式,这样的整合,也可以,但是我个人觉得有点多余。因为这样仅仅是一个FactoryBean和@Bean高级注解的一个联合使用。

正常情况下,我们直接在@Bean代码中写就行了,以上的这种联合使用,我们经常用来遗留系统的整合当中进行使用

4):@Bean注解自定义id值

就在@Bean当中添加一个参数就行了,@Bean(“name”)这样就实现了

5):@Bean控制对象创建次数

只需要在@Bean修饰的方法上,加上一个@Scope注解就可以了
当然这样的话,@Bean和FactoryBean联合用来整合遗留系统的这个方式,里边的isSingleton方法就失效了。默认不写的时候,是单例设计模式。

2:@Bean注入

1):自定义类型注入

在我们的配置Bean当中,我们通过@Bean注解配置一个UseDao对象,我们这一步完成的就是所要进行注入的对象的创建。

通过@Bean注解创建一个UseService对象,通过这个返回值 返回一个UseService对象,他里边的注入操作是通过形参来体现的,UseService依赖UserDao,将dao作为形参,创建对象的时候完成注入,使用set方法进行注入,这就等价于之前的propery标签,这样就完成了注入,最终我们把完整性UserService完成了注入,注入:一个是依赖作为形参,二是调用set方法进行注入即可。

@Configuration
public class AppConfig1 {

    @Bean
    public UserDao userDao(){
        return new UserDaoImpl();
    }

    @Bean
    public UserService userService(UserDao userDao) {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        return userService;
    }


}
    @Test
    public void testEight(){
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig1.class);
        UserService userService = (UserService)ctx.getBean("userService");
        userService.register();
    }
2021-08-13 08:19:16.974
                [main] INFO  org.springframework.core.KotlinDetector - Kotlin reflection implementation not found at runtime, related features won't be available.
2021-08-13 08:19:17.050
                [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4567f35d
2021-08-13 08:19:17.061
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
2021-08-13 08:19:17.197
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
2021-08-13 08:19:17.200
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
2021-08-13 08:19:17.202
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
2021-08-13 08:19:17.203
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
2021-08-13 08:19:17.209
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'appConfig1'
2021-08-13 08:19:17.214
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userDao'
2021-08-13 08:19:17.236
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userService'
2021-08-13 08:19:17.244
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'userService' via factory method to bean named 'userDao'
UserServiceImpl.register
UserDaoImpl.save

用户自定义类型的注入就是通过这种类型来完成的,除了这种方式可以在@Bean当中进行注入的形式以外,我们还有更加简单的方式,开始还是需要先创建UserDao的对象,后边就是创建UserService的时候进行一个注入的时候,不采用这种形参的方式,而是采用userDao的方法的调用进行获取对象,进而通过set方法进行注入。因为相似度很高,我就不写了

2):JDK类型的注入

对于JDK类型的注入,我们我们之前直接通过property标签进行赋值,他的本质也是调用set方法,但是现在我们通过@Bean高级注解进行开发的时候,我们就需要时候用set方法进行赋值,现在的注入方式都是程序员显示的去调用set方法进行注入赋值操作,原来的时候,代码太简单,我们就不写了。这个和我们使用用户自定义类型进行注入的时候是没有任何区别的,本质上都是采用手工set注入的方式进行注入。要真的需要说明区别的话,就是用户自定义类型是需要生命形参的。

3):JDK类型注入细节分析

set注入的时候我们需要注意耦合的问题

我们通过@PropertySource(“classpath:/init.properties”)注解将配置文件引入到Spring当中,在@Value注解进行赋值注入操作,这样我们就解决了自定义类型的注入的问题

@Configuration
@PropertySource("classpath:/init.properties")
public class AppConfig1 {

    @Value("${id}")
    private Integer id;

    @Value("${name}")
    private String name;

    @Bean
    public Customer Customer(){
        Customer customer = new Customer();
        Customer.setId();
        Customer.setName();
        return cumtomer;
    }

}

第三章:@ComponentScan

之前我们在核心配置文件当中context:component-san标签,用于进行包扫描然而现在我们包扫描注解就完全可以取代这个标签的作用

我们这个Component-scan注解是应用在配置Bean上边,引入他最终的目的就是为了来扫描Spring的基础注解,@Component及其衍生注解@Value@Autowired,这就是这个注解的核心作用。

一:@ComponentScan基本使用

<context:component-scan base-package = "com.dashu"/>

在这标签当中我们有一个属性base-package制定了要进行包扫描的包和子包,用注解进行替换之后,我们就一定是应用在配置Bean上边,也就是说在@Configuration注解修饰的类上加上这个注解之后,用于扫描对应包下基本注解,进而进行基本对象的创建。

有了这两个注解之后,这个配置Bean就可以称为真正意义上的配置Bean了。我们就不需要写任何标签了。因为在标签当中有一个base-packages属性,在注解当中也需要指定这个属性。

    @Test
    public void testNine(){
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig2.class);
        String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        //user1
        //user2
    }

/**
 * @Auther: DaShu
 * @Date: 2021/8/13 09:02
 * @Description:
 */
@Component
public class User1 {
}

/**
 * @Auther: DaShu
 * @Date: 2021/8/13 09:02
 * @Description:
 */
@Component
public class User2 {
}

二:@ComponentScan排除策略

当我们使用标签进行开发的时候,我们使用的排除策略就是通过这样的:在标签配置当中有一个字标签,这个子标签叫做<context:exclude-filter type =“”…通过这种排除策略可以排除定义包扫描之内的一些类进行排除操作。

当然我们基于注解呢,肯定也是进行一个排除策略的操作的,注解的属性和属性之间需要有逗号分割。排除策略的值是一个数组,因为排除策略是可以叠加的,我们可以通过配置多个排除策略完成排除策略的叠加。type属性对应之前的type标签,后边的value可以对应具体排除策略。也就是对应之前的expression,使用注解的和标签的这种形式的表现上有一点点差异,但是在要点上确实没啥区别。**
在这里插入图片描述

@Configuration
@ComponentScan(basePackages = "com.dashu.scan",
        excludeFilters={@ComponentScan.Filter(type= FilterType.ANNOTATION,value ={ Service.class})})
public class AppConfig2 {

}

通过这个操作,我们扫描com.dashu.scan包下的类,排除@Service注解修饰的类,这样我们就会创建User1的对象,不会创建User2的对象。作为排除类型一共有五种,五种排除方式的话自己进行复习就好了

@Configuration
@ComponentScan(basePackages = "com.dashu.scan",
        excludeFilters={@ComponentScan.Filter(type= FilterType.ANNOTATION,value ={ Service.class}),
                        @ComponentScan.Filter(type= FilterType.ASPECTJ,pattern ={"com.dashu..*"})})
public class AppConfig2 {

}

这样写的话,就排除了注解的方式以及切面的方式,我们使用标签的方式定义排除策略的时候,我们通过expression的形式代表排除具体内容值,但是当我们使用注解的时候,我们的注解的时候就不是expression了,而是value,pattern基于注解排除的时候,待会需要进行一个完善

三:@ComponentScan包含策略

包含方式决定了只扫描哪些类上的注解,这些也对应当初标签配置开发的时候的属性,只需要有一个<componenet-scan这个属性就可以了。

但是我们使用这个标签的时候,必须先配置一个use-default-filters="false"这样的属性,来让Spring放弃他自己的扫描策略,而是使用我们自己的扫描策略。所以这个属性必须指定为false,之后我们就基于各种各样的方式进行配置扫描策略就可以了。
在这里插入图片描述

第四章:Spring工厂创建对象多种配置方式

一:多种配置方式的应用场景

我们创建一个User对象的话,我们有多种配置方式,比如使用@Component注解对他进行配置,也可以@Bean对他进行配置,也可以使用Bean标签对应进行配置,那么这些配置都适用于什么样的应用场景呢?

1:@Componenet注解,及其衍生注解,来讲主要应用程序员自己开发的类型上,程序员自己写的,程序要可以加上这些注解,也就可以进行创建对象和注入

2:@Bean这些对象,他也能创建对象,他用于框架提供的类型和别的程序员创建的类型,这样的类型都有一个特点,没有源码,所以,我们只能通过@Bean方法方法创建对象的形式来进行对象的创建,比如Connection对象和SqlSessionFactoryBean这个对象的创建,MapperScannerConfigure这个对象的创建。

3:bean标签这种形式我们基于纯注解开发过程中我们是基本不适用的,我们基本上只在遗留系统的整合上,可能用到这种形式,遗留提供很多年以前,没有使用注解,很多都是原生的创建。

4:Spring还为我们提供了一种基于@Import注解创建对象的方式,我们可以在配置Bean的上边使用这个注解,当我们在这个注解当中执行Class对象类型的时候,Spring创建配置Bean对象的同时也会把这个Class对象创建出来,这个@import注解也是可以让Spring工厂为我们进行对象创建的。

例如一个配置Bean当中,Spring会为我们创建他的对象,但是如果我们在他上边加了一个@Import(“User.class”)这样创建这个对象的同事也会把User这个对象创建出来。这个方式基本上是Spring底层自己使用的。

作为这个注解,我们很少用,什么时候会用呢,第一个场景是:一般是Spring框架的底层会使用,因为这种方式通过会集成其他的特性一起使用,Spring框架底层会使用,第二个场景是:这个经常会用在多配置Bean整合的时候,多配置Bean的整合上边,我们后续单独进行讲解分析。

    @Test
    public void testNine(){
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig2.class);
        String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        //appConfig2
        //user1
        //user2
        //user
    }

@Configuration
@Import(User.class)
@ComponentScan("com.dashu.scan")
public class AppConfig2 {

}

二:多种配置方式优先级

多种配置方式优先级也是不一样的,@Component <@Bean< 配置文件中的Bean标签

优先级搞的配置覆盖优先级配置低的配置,当我们配置低的形式创建对象的内容不满意的时候,我们无需对他进行修改,只需要采用更高级的形式进行覆盖即可,进行配置覆盖的过程中,有一个前提,这个id值必须保持一致,只有保持一致才能够进行覆盖,只有当id配置一致的时候才能够进行覆盖。

三: 解决注解配置的耦合问题

注解配置的耦合问题来源于,我们创建复杂对象时直接在@Bean当中使用了new操作,当我们遇到这种耦合问题的时候。

我们如何进行解决呢,就是需要使用这样的一个高级的配置实现覆盖,比如所使用bean标签,我们可以在class标签当中使用新的注入,这样就解决了耦合的问题,只需要保持一个id值相同就可以了,只需要在Spring配置Bean当中引入Spring的核心配置文件,这样就可以实现对象的覆盖,也就解决了耦合的问题
在这里插入图片描述
但是这样也产生了一个新的问题,我们在配置Bean当中引入Spring核心配置文件之后,我们就修改原有的配置Bean,这不有增加了耦合性了么,实际上我们不引入这个配置Bean也是可以的。

我们可以这样实现,我们提供一个新的配置Bean,我们在新的配置Bean当中添加一个引入核心配置文件,这样设计是符合开闭设计原则的,后续我们让新的和旧的配置Bean一起起作用,这样的话,想让他们同时生效的话,只需要在Spring的工厂创建爱你的时候将两个配置Bean作为参数传递进去就好了,后续我们想让更多的配置Bean生效的话,我们甚至可以这样。**
在这里插入图片描述

第五章:整合多个配置信息

一:为什么会有多个配置信息呢?

真正的项目中会有N多个配置Bean的,根据内容进行拆分,拆分的原则是,按照功能进行查分,Spring和Mybatis、事务控制、都有自己独立的配置Bean
在这里插入图片描述
在这里插入图片描述

二:如何将多个配置信息整合在一起

1:整合要点

1:多配置Bean的整合
2:多配置Bean和@Component进行整合
3:多配置Bean和ApplicationContext.xml进行整合:配置覆盖,整合遗留系统

1、如何使多配置信息汇总成一个整体?
2、如何实现跨配置的注入?比如注解当中创建的对象注入给Bean标签当中

2:多配置Bean的整合

在整个处理的过程当中,我们需要关注两个要点:一个是如何整合,一个是如何夸配置注入。

整合其实很简单,只需要在创建Spring工厂对象的时候指定包扫描就可以了,当我们制定了扫描的包之后,创建工厂对象的时候就可以通过包扫描创建这些配置Bean的对象了,进而实现多个配置Bean的整合,这个解决方案,非常类似于我们当时多xml配置文件的整合。
在这里插入图片描述

    @Test
    public void testTen(){
        ApplicationContext ctx = new AnnotationConfigApplicationContext("com.dashu.config");
        UserDao userDao  = (UserDao) ctx.getBean("userDao");
        UserService userService = (UserService) ctx.getBean("userService");
        System.out.println(userDao);
        System.out.println(userService);
        //com.dashu.injection.UserDaoImpl@6e2aa843
        //com.dashu.injection.UserServiceImpl@6f36c2f0
    }
@Configuration
public class Appconfig2 {
    @Bean
    public UserDao userDao (){
        UserDaoImpl userDao = new UserDaoImpl();
        return userDao;
    }
}

@Configuration
public class Appconfig1 {
    @Bean
    public UserService userService (){
        UserServiceImpl userService = new UserServiceImpl();
        return userService;
    }
}

2021-08-13 21:16:06.479
                [main] INFO  org.springframework.core.KotlinDetector - Kotlin reflection implementation not found at runtime, related features won't be available.
2021-08-13 21:16:06.595
                [main] DEBUG o.s.c.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\giteesource\spring\spring-annotation\target\classes\com\dashu\config\Appconfig1.class]
2021-08-13 21:16:06.596
                [main] DEBUG o.s.c.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [D:\giteesource\spring\spring-annotation\target\classes\com\dashu\config\Appconfig2.class]
2021-08-13 21:16:06.602
                [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4567f35d
2021-08-13 21:16:06.627
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
2021-08-13 21:16:06.787
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
2021-08-13 21:16:06.789
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
2021-08-13 21:16:06.791
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
2021-08-13 21:16:06.792
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
2021-08-13 21:16:06.808
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'appconfig1'
2021-08-13 21:16:06.815
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'appconfig2'
2021-08-13 21:16:06.816
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userService'
2021-08-13 21:16:06.865
                [main] DEBUG o.s.b.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userDao'
com.dashu.injection.UserDaoImpl@6e2aa843
com.dashu.injection.UserServiceImpl@6f36c2f0

使用@Import注解完成多个配合Bean的整合,在Spring创建第一个对象的时候,也会把第二个配置Bean的对象进行创建,这样干偏底层,创建工厂对象的时候只需要指定第一个config配置Bean就可以了,这个跟XML多个整合的方式是一模一样的。

这里体现了@import的两个作用,第一个是创建对象,第二个是多配置Bean的整合。
在S在这里插入图片描述在这里插入图片描述

    @Test
    public void testEleten(){
        ApplicationContext ctx = new AnnotationConfigApplicationContext(Appconfig1.class);
        UserDao userDao  = (UserDao) ctx.getBean("userDao");
        UserService userService = (UserService) ctx.getBean("userService");
        System.out.println(userDao);
        System.out.println(userService);
        //com.dashu.injection.UserDaoImpl@6e2aa843
        //com.dashu.injection.UserServiceImpl@6f36c2f0
    }
/**
 * @Auther: DaShu
 * @Date: 2021/8/13 21:09
 * @Description:
 */
@Configuration
@Import(Appconfig2.class)
public class Appconfig1 {
    @Bean
    public UserService userService (){
        UserServiceImpl userService = new UserServiceImpl();
        return userService;
    }
}
/**
 * @Auther: DaShu
 * @Date: 2021/8/13 21:09
 * @Description:
 */
@Configuration
public class Appconfig2 {
    @Bean
    public UserDao userDao (){
        UserDaoImpl userDao = new UserDaoImpl();
        return userDao;
    }
}

3:跨配置Bean进行注入

跨配置进行相应的注入,只需要将需要注入的内容在需要注入的配置Bean当中作为一个成员变量,然后使用一个@Autowired注解给她进行注入即可。这样就能完成一个跨配置的注入。这样的配置方式适用于使用配置Bean所有的场景。

    @Test
    public void testEleten2() {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(Appconfig1.class);
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        UserService userService = (UserService) ctx.getBean("userService");
        userService.register();
        //UserServiceImpl.register
        //UserDaoImpl.save
    }
@Configuration
@Import(Appconfig2.class)
public class Appconfig1 {

    @Autowired
    private UserDao userDao;

    @Bean
    public UserService userService (){
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        return userService;
    }
}

/**
 * @Auther: DaShu
 * @Date: 2021/8/13 21:09
 * @Description:
 */
@Configuration
public class Appconfig2 {
    @Bean
    public UserDao userDao (){
        UserDaoImpl userDao = new UserDaoImpl();
        return userDao;
    }
}

4:配置Bean整合@Component

我们自己定义的类可以使用@Component及其衍生注解,这样我们的此时我们想把这二个进行整合,我们学过这个概念,我们只需要在配置Bean上边加上包扫描注解即可。在这里边实现跨配置进行注入的话和上边是没有任何区别的。都是采用@Autowired进行注即可。
在这里插入图片描述

5:配置Bean与配置文件的整合

1):应用场景

1:遗留系统
2:配置覆盖

2):@ImportResource

这里的整合是使用了@ImportResource注解,上边指定配置文件的路径,如果放在了跟路径下边,那么就是如下的写法。

注入的话和其他的地方是没有任何区别的,就是通过@Autowired注解加上一个,一个set注入即可。
在这里插入图片描述

三:Bean的底层实现原理

在创建一个配置Bean的时候,需要在配置Bean当中,添加一个@Configuration注解,后续工厂对象创建的时候,就会创建配置Bean和配置Bean当中的对象了。

实际上,这块有一个细节是需要关注的,作为Spring来讲,Spring在读取到配置Bean的时候,调用配置Bean当中程序员写好的创建对象的方法来创建对象。我们获取对象的话,获取的事Spring帮我们创建好的对象,那么Spring是如何做到只创建一次的呢?

我们书写了创建对象的功能,被Spring调用之后,Spring调用之后,他控制了对象的创建次数,创建对象初始功能,控制对象的创建次数是额外功能,也就是Spring采用了代理设计模式,进行了控制对象创建的额外功能。

整个配置Bean最为核心的功能采用了Aop的方式进行开发的,Aop的开发一种是基于JDK的,另外一种是采用Cglib的创建方式,显然配置Bean是采用Cglib这种形式的,整个配置Bean实际上采用的就是代理设计模式。

底下的这个图就证明了所谓的配置Bean对象就是Cglib创建的代理对象,可以控制对象的创建。整个配置Bean的底层就是代理设计模式。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/45393.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Prometheus+Grafana部署

一 、Prometheus 源码安装和启动配置 普罗米修斯下载网址&#xff1a;https://prometheus.io/download/ 监控集成器下载地址&#xff1a;http://www.coderdocument.com/docs/prometheus/v2.14/instrumenting/exporters_and_integrations.html 1.实验环境 IP角色系统172.16.1…

理解浅拷贝和深拷贝以及实现方法

一、数据类型 数据分为基本数据类型(String, Number, Boolean, Null, Undefined&#xff0c;Symbol)和引用数据类型Object&#xff0c;包含&#xff08;function&#xff0c;Array&#xff0c;Date&#xff09;。 1、基本数据类型的特点&#xff1a;直接存储在栈内存中的数据 …

品牌投资与形象全面升级 | 快来认识全新的 Go 旅城通票

近日&#xff0c;Go 旅城通票&#xff08;Go City&#xff09;品牌全面升级&#xff0c;旨在提高旅游爱好者对品牌的认知。从新冠疫情大流行中阴霾中走出来的 Go 旅城通票复苏势头强劲&#xff0c;专注于技术提升&#xff0c;使命是协助旅游爱好者无论到世界各地的哪一个城市畅…

在线分析网站日志软件-免费分析网站蜘蛛的软件

搜索引擎蜘蛛的作用是什么&#xff1f;我们网站上的内容如果要想被搜索引擎收录并且给予排名&#xff0c;就必须要经过搜索引擎蜘蛛的爬取并且建立索引。所以让搜索引擎蜘蛛更好的了解我们的网站是很重要的一步&#xff01;搜索引擎蜘蛛在爬取某个网站&#xff0c;是通过网站的…

浅谈虚拟地址转换成物理地址(值得收藏)

这里&#xff0c;我们讲解一下Linux是如何将虚拟地址转换成物理地址的 一、地址转换 在进程中&#xff0c;我们不直接对物理地址进行操作&#xff0c;CPU在运行时&#xff0c;指定的地址要经过MMU转换后才能访问到真正的物理内存。 地址转换的过程分为两部分&#xff0c;分段…

Linux systemctl 详解自定义 systemd unit

Linux systemctl 详解&自定义 systemd unit systemctl 序 大家都知道&#xff0c;我们安装了很多服务之后&#xff0c;使用 systemctl 来管理这些服务&#xff0c;比如开启、重启、关闭等等&#xff0c;所以 systemctl 是一个 systemd 系统。centos 使用 systemctl 来代…

9.8 段错误,虚拟内存,内存映射 CSAPP

相信写代码的或多或少都会遇到段错误&#xff0c;segmentation fault. 今天终于看到这里面的底层原理 参考&#xff1a; https://greenhathg.github.io/2022/05/18/CMU213-CSAPP-Virtual-Memory-Systems/18-Virtual-Memory-SystemsSimple memory system exampleAddress Trans…

(转)CSS结合伪类实现icon

老规矩&#xff0c;还是先说说业务场景&#xff1a;有一个图片列表&#xff0c;可以添加、删除和更改&#xff0c;其中呢删除时设计给的设计稿时悬浮&#xff08;hover&#xff09;在图片上时显示删除的图标&#xff0c;所以就有了这个用before实现icon的场景 进入正文&#xf…

嵌入式系统开发笔记108:IO的使用方法与面向对象程序设计

文章目录前言一、IO引脚的基本概念二、映射层的设置1、映射层是原理图的直译层2、IO引脚的设置在hal.h 和 hal.cpp文件中完成&#xff08;1&#xff09;在hal.h中进行类定义&#xff08;2&#xff09;在hal.cpp中完成引脚映射三、面向对象程序设计思想1、程序设计分类2、举例3、…

DevExpress之C#界面+MATLAB动态链接库联合编程

MATLAB导出动态链接库 在MATLAB命令行中输入:deploytool,打开如下界面,选择Library Compiler 对于C#,选择.NET Assembly,点击右侧的“+”加号,添加要导出的函数 可添加多个函数 下面的类名中输入即为导出后类的名称 点击设置按钮,输入参数-C,参数的具体含义如下 …

简化MRO工业品供采交易路径,S2B2B商城助力企业构建业务一体化管理优势

在政策拉动、市场需求驱动及数字技术进步等多重力量共同作用下&#xff0c;近5年来&#xff0c;我国工业品B2B市场规模保持上升的态势。尽管2022年受疫情反复影响&#xff0c;但中国经济向好的局面并未改变&#xff0c;中国数字化经济依然会加快工业品B2B市场的发展&#xff0c…

绿色债券数据集2016-2021(含交易代码、债券简称、发行规模期限等多指标数据)

1、数据来源&#xff1a;wind 2、时间跨度&#xff1a;2016.01-2021.11年 3、区域范围&#xff1a;全国 4、指标说明&#xff1a; 部分指标如下&#xff1a; 交易代码 债券简称 发行起始日 缴款日 计划发行规模(亿) 发行金额上…

第四章. Pandas进阶—时间序列

第四章. Pandas进阶 4.9 时间序列 1.重采样&#xff08;resample&#xff09; 在Pandas中&#xff0c;对时间序列频率的调整称为重采样&#xff0c;即时间序列从一个频率转换到另一个频率的过程&#xff0c;由周统计变成月统计 1).语法&#xff1a; 4.8章 第4点 已介绍过&…

5G无线技术基础自学系列 | MIMO功能

素材来源&#xff1a;《5G无线网络规划与优化》 一边学习一边整理内容&#xff0c;并与大家分享&#xff0c;侵权即删&#xff0c;谢谢支持&#xff01; 附上汇总贴&#xff1a;5G无线技术基础自学系列 | 汇总_COCOgsta的博客-CSDN博客 无线通信的迅速发展对系统的容量和频谱…

天启星座(Tianqi)介绍

天启星座&#xff08;Tianqi&#xff09;由38颗卫星组网而成&#xff0c;提供全球短数据采集。致力于为全球物联网相关行业用户提供覆盖全球、准实时的物联网卫星数据服务&#xff0c;真正实现空中、海洋和地面的万物互联&#xff0c;构建天地一体化的卫星物联网生态系统&#…

stm32 笔记 UART读取及HAL库应用

基本流程图 由此图可知&#xff1a; 采用HAL库&#xff0c;中断方式接收串口&#xff0c;只有当RxXferCount 0 时&#xff0c;也就是调用这个函数&#xff0c;接收指定量的数据大小完成时&#xff0c;才会调用回调函数HAL_UART_RxCpltCallback()。 而且&#xff0c;RxXferCou…

技术资料:STM32F746NGH7,STM32L471ZGT6 IC MCU+FPU

描述&#xff1a;STM32F7 32 位 MCUFPU 基于高性能的 ARMCortex-M7 32 位 RISC 内核&#xff0c;工作频率高达 216MHz。Cortex-M7 内核具有单浮点单元(SFPU)精度&#xff0c;支持所有 ARM 单精度数据处理指令与数据类型。同时执行全套 DSP 指令和存储保护单元&#xff08;MPU&a…

ThreadLocal源码解析 2.ThreadLocalMap内核

ThreadLocal源码解析—ThreadLocalMap内核 简介 内部类 ThreadLocalMap 才是 ThreadLocal 的真正核心。 ThreadLocalMap 与 HashMap不一样&#xff0c;HashMap 中的数据结构有数组&#xff0c;链表还有红黑树&#xff1b;而 ThreadLocalMap 中的数据结构只有数组。HashMap 处…

反转链表与拓展【灵神基础精讲】

来源0x3f&#xff1a;https://space.bilibili.com/206214 文章目录反转链表[206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/)[92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/)[25. K 个一组翻转链表](https://leetcode.cn/proble…

[附源码]Python计算机毕业设计Django仓储综合管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…