Spring基础篇:高级注解编程

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Spring基础篇:高级注解编程


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的整合。

@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的底层就是代理设计模式。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1月前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
50 0
|
2月前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
129 3
|
12天前
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
一键注入 Spring 成员变量,顺序编程
|
23天前
|
前端开发 Java Spring
Spring MVC核心:深入理解@RequestMapping注解
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的核心,它将HTTP请求映射到控制器的处理方法上。本文将深入探讨`@RequestMapping`注解的各个方面,包括其注解的使用方法、如何与Spring MVC的其他组件协同工作,以及在实际开发中的应用案例。
36 4
|
1月前
|
XML JSON Java
SpringBoot必须掌握的常用注解!
SpringBoot必须掌握的常用注解!
61 4
SpringBoot必须掌握的常用注解!
|
23天前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
68 2
|
23天前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
40 2
|
26天前
|
消息中间件 Java 数据库
解密Spring Boot:深入理解条件装配与条件注解
Spring Boot中的条件装配与条件注解提供了强大的工具,使得应用程序可以根据不同的条件动态装配Bean,从而实现灵活的配置和管理。通过合理使用这些条件注解,开发者可以根据实际需求动态调整应用的行为,提升代码的可维护性和可扩展性。希望本文能够帮助你深入理解Spring Boot中的条件装配与条件注解,在实际开发中更好地应用这些功能。
31 2
|
26天前
|
JSON Java 数据格式
springboot常用注解
@RestController :修饰类,该控制器会返回Json数据 @RequestMapping(“/path”) :修饰类,该控制器的请求路径 @Autowired : 修饰属性,按照类型进行依赖注入 @PathVariable : 修饰参数,将路径值映射到参数上 @ResponseBody :修饰方法,该方法会返回Json数据 @RequestBody(需要使用Post提交方式) :修饰参数,将Json数据封装到对应参数中 @Controller@Service@Compont: 将类注册到ioc容器
|
27天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
38 2
下一篇
DataWorks