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 source命令
    pythoy 基础一: python的特点 if 语句 whlie语句
    linux 基础
    python的游戏之旅( 数字 字符串 列表 元组 字典 即为游戏职业)
    html 基础
    《SQL Server 2008 从入门到精通》 学习笔记 第五天
    [转载] Visual Studio 2010 MSDN Help Library文档位置、错误、重新安装及安装注意事项
    ASP.NET后台通过输出JavaScript弹出窗口小结
    网上搜集的webbrower的资料,很有借鉴价值
    解决MSSQL 2008不能用IP登录的问题 和 打开可以用SA登录SQL2008的方法
  • 原文地址:https://www.cnblogs.com/develon/p/14506494.html
Copyright © 2011-2022 走看看