zoukankan      html  css  js  c++  java
  • @Configuration 注解的用途

    why

    Spring实战中说:

    默认情况下,Spring中的bean都是单例的,我们并没有必要创建第二个完全相同(甚至可能不同,由@Bean注解的方法提供)的Bean实例。


    ......

    借助JavaConfig实现注入

    看起来,CompactDisc是通过调用sgtPeppers()得到的,但情况并非完全如此。
    因为sgtPeppers()方法上添加了@Bean注解,Spring将会拦截所有对它的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用。

    @Configuration

    现在我们知道为什么有以下几个规则的原因了:

    1. @Configuration注解的类都必须是open类(类可以隐式地子类化,并且不能是最终的);
    2. @Configuration中的@Bean方法必须可重写;
    3. 为什么有@Configuration注解,明明@Component一样可以配置Bean;

    因为@Bean方法会被代理拦截!

    @Configuration
    open class A : InitializingBean, ApplicationContextAware {
        @Bean open fun getStr(): String { // 该方法实际只会被调用一次
            println("@Bean方法被调用")
            return "Hello"
        }
    
        var ctx: ApplicationContext? = null
        override fun afterPropertiesSet() {
            var value = ctx!!.getBean(String::class.java)
            println("bean = $value")
            value = getStr() // getStr被代理!
            println("bean = $value")
            value = getStr()
            println("bean = $value")
        }
    
        override fun setApplicationContext(applicationContext: ApplicationContext) {
            this.ctx = applicationContext
        }
    }
    

    输出是:

    @Bean方法被调用
    bean = Hello
    bean = Hello
    bean = Hello
    

    @Bean方法确实只被调用了一次,实在是匪夷所思。

    测试

    package test
    
    import org.junit.Assert
    import org.junit.Test
    import org.junit.runner.RunWith
    import org.springframework.beans.factory.annotation.Autowired
    import org.springframework.context.ApplicationContext
    import org.springframework.context.annotation.Bean
    import org.springframework.context.annotation.ComponentScan
    import org.springframework.context.annotation.Configuration
    import org.springframework.test.context.ContextConfiguration
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
    import java.util.*
    
    @RunWith(SpringJUnit4ClassRunner::class)
    @ContextConfiguration(classes = [TestConfigBean::class])
    @ComponentScan
    class TestConfigBean {
        @Autowired lateinit var ctx: ApplicationContext
    
        @Test fun `时间戳正确性`() {
            val ta = currentTimeStamp()
            val tb = currentTimeStamp()
            println(ta)
            println(tb)
            Assert.assertNotEquals(ta, tb)
        }
    
        @Test fun `@Bean会被代理`() {
            val beanA = ctx.getBean(BeanA::class.java)
            println(beanA.productBeanA())
            println(beanA.productBeanA())
            Assert.assertEquals(beanA.productBeanA(), beanA.productBeanA())
        }
    }
    
    @Configuration    // <------- 此处如果换成@Component或者@Service,测试都会失败!说明只有使用@Configuration注解的类才会被代理
    open class BeanA {
        @Bean
        open fun productBeanA(): TimeStamp {
            println("only once!")
            return currentTimeStamp()
        }
    }
    
    data class TimeStamp(val value: Long)
    fun currentTimeStamp(): TimeStamp {
        Thread.sleep(1)
        return TimeStamp(Date().time)
    }
    
  • 相关阅读:
    Linux下如何查看版本信息
    linux的top命令参数详解
    浅谈Linux内存管理机制
    python3 判断字符串是否为纯空格组成的方法
    python3 字符串/列表/元组(str/list/tuple)相互转换方法及join()函数的使用
    python3 json数据格式的转换(dumps/loads的使用、dict to str/str to dict、json字符串/字典的相互转换)
    python3 list列表随机选取一个元素、随机选择一个user-agent
    windows系统中,在当前目录下打开cmd命令行的两种方法
    name 'reload' is not defined解决方法
    Vue.js05:vue内联样式
  • 原文地址:https://www.cnblogs.com/develon/p/14506494.html
Copyright © 2011-2022 走看看