• @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)
    }
    
  • 相关阅读:
    指针数组/数组指针
    hdu 5053 the Sum of Cube(上海网络赛)
    Archlinux YouCompleteMe+syntastic vim自己主动补全插件,显示缩进和状态栏美化,爽心悦目的vim
    sgu139Help Needed!推断15数码是否有解,以及推断N数码是否有解的推论
    hdu 4932 Miaomiao&#39;s Geometry(暴力)
    Theano学习笔记(一)——代数
    Tomcat全攻略
    send,recv,sendto,recvfrom
    git合并远端分支到本地分支的两种方式
    php实现记忆化递归--以斐波那契数列为例(还是以边学边做为主,注重练习)
  • 原文地址:https://www.cnblogs.com/develon/p/14506494.html
Copyright © 2020-2023  润新知