spring @Bean注解

spring @Bean注解

起男 1,567 2020-07-31

spring @Bean注解

spring的@Bean注解用于告诉方法,产生一个bean对象,然后交给spring管理

基本使用

@Configuration
public class MyConfig {

    /**
     * bean的名称默认是方法的名称
     * 也可以使用@Bean的name和value属性进行设置
     * @return
     */
    @Bean
    //@Bean("bean1")
    public MyBean myBean(){
        return new MyBean();
    }
}

注:@Bean其实并不一定要在@Configuration注解中,我会在之后进行说明

属性详解

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
    @AliasFor("name")
    String[] value() default {};

    @AliasFor("value")
    String[] name() default {};

    /** @deprecated */
    @Deprecated
    Autowire autowire() default Autowire.NO;

    boolean autowireCandidate() default true;

    String initMethod() default "";

    String destroyMethod() default "(inferred)";
}
属性名作用
value和name互为别名,为当前bean指定一个名称,可以设置多个
name和value互为别名,为当前bean指定一个名称,可以设置多个
autowire表示自动装配的类型,接收一个Autowire枚举,
默认NO表示没有自动装配
BY_NAME表示通过名称自动装配
BY_TYPE表示通过类型自动装配
autowireCandidate容器在进行自动装配时是否考虑此对象,默认考虑
initMethod指定初始化时调用的方法
destroyMethod指定销毁时调用的方法

相关注解

@Configuration

上面说到@Bean并不一定需要@Configuration内使用,其实在其它如@Component标签中使用也是可以的,但和在@Configuration中有一定的差异

full模式和lite模式

  • lite模式:在没有标注@Configuration的类里有@Bean方法就称为lite模式
    • 在该模式下容器里的bean是它本身,不会被cglib增强
    • 由于cglib是创建子类代理,而它不进行cglib增强,故@Bean方法可以是private、final修饰的
    • 该模式下不能通过方法调用来获取依赖
    • 由于不进行cglib,故运行性能略高,降低了启动时间
  • full模式:在有标注@Configuration的类里有@Bean方法就称为full模式
    • 在该模式下配置类会被cglib增强,放入容器的是它的代理
    • 由于cglib是创建子类代理,故@Bean方法 不能是private、final修改的,因为子类拿不到
    • 该模式下可以通过方法调用来获取依赖
    • 由于通过了cglib增强,故对新手的友好型更好

注:也可以通过@Configuration中的proxyBeanMethods属性设置lite模式还是full模式,默认full

@Profile

可以根据当前环境,动态的激活和切换一系列组件的功能

设置环境

spring环境下可以通过context.getEnvironment().setActiveProfiles("xxx");修改环境变量

springboot中可以通过spring.profiles.active=xxx指定运行环境

使用范围

@Configuration或其它类级别bean注解修饰的类上

@Bean方法上

环境可以设置多个,也可以使用!占位符

@Scope

设置bean的作用域

属性作用
singeton默认值,单例的,在项目启动时创建并加载到容器
prototype多例的,在获取bean时创建
requestbean对象的生命周期是一次http请求
sessionbean对象的生命周期是一次http会话
applicationbean对象的生命周期在servletContext生命周期内
websocketbean对象的生命周期在webSocket生命周期内
globalsession类似于session,但只在portlet的web应用中生效

注:requst、session、application、websocket不能用于普通项目,只能在web项目中生效

proxyMode

该属性决定了被注解的类是否会被代理,值是一个枚举

ScopedProxyMode:

作用
DEFAULT不是代理目标的bean
NO不是代理目标的bean
INTRFACES使用jdk动态代理
TARGET_CLASS使用cglib动态代理

@Lazy

表示一个bean是否是懒加载(延迟加载)的

  • 可以作用于方法上,表示这个方法被延迟加载
  • 可以作用在被@Component或其子注解注释的类上,表示这个类中所有的bean都被延迟加载
  • 如果没有注释@Lazy或属性设置为false,那么该bean不会被懒加载
  • 还可以作用在@Autowired和@Inject注解的属性上,这种情况下,他将为该字段创建一个惰性代理

@DependsOn

指定当前bean所依赖的bean,任何被依赖的bean都能保证在当前bean之前创建,可以控制bean的加载顺序

@Description

对bean添加描述

有时候需要提供一个详细的bean描述文本是非常有用的

当对bean暴露进行监控时,非常有用

@Conditional

根据某个条件创建特点的bean,通过实现condition接口,并重写matches接口来构建判断条件

扩展注解

注解创建bean的时机
@ConditionalOnBean在当前上下文中存在某个bean时
@ConditionalOnClass某个class位于类路径上时
@ConditionalOnExpression当表达式为true时
@ConditionalOnMissingBean当前上下文中不存在某个bean时
@ConditionalOnMissingClass某个class不存在于类路径上时
@ConditionalOnNotWebApplication不是web应用
@ConditionalOnWebApplication是web应用
@ConditionalOnProperty当指定属性有指定值时
@ConditionalOnJava当jvm为指定版本时
@ConditionalOnResource当类路径下有指定资源时
@ConditionalOnJndi在jndi存在条件下时
@ConditionalOnSingleCandidate指定bean在容器中只有一个,或有多个但指定了首选

@Primary

当有多个bean符合依赖注入时,最优先考虑的bean

可以和@Bean或@Component一起使用

@Import

@Import通过快速导入的方式实现把实例加入spring的ioc容器中

@Import的三种用法

  1. 直接填class数组

    //通过这种方式添加的bean bean名是全类名
    @Import({MyBean.class})
    public class MyImport {
    }
    
  2. ImportSelector方式

    //通过这种方式添加的bean bean名是全类名
    @Import({MyBean.class, MySelector.class})
    public class MyImport {
    }
    
    public class MySelector implements ImportSelector {
    
        /**
         * 实现接口中的方法
         * @param annotationMetadata 表示当前被@Import注解给标注的所有注解信息
         * @return 实际要导入到容器中的组件全类名,可返回空数组,但不可用直接返回null
         */
        @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            return new String[]{"com.dqn.beanann.beananndemo.pojo.MyDemo"};
        }
    }
    
  3. ImportBeanDefinitionRegistrar方式

    //这种方式可以指定bean的名称
    @Import({MyBean.class, MySelector.class, MyRegistran.class})
    public class MyImport {
    }
    
    public class MyRegistran implements ImportBeanDefinitionRegistrar {
    
        /**
         *
         * @param importingClassMetadata 和importSelector的参数一样表示当前被@Import注解给标注的所有注解信息
         * @param registry 可用于注册bean
         */
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                            BeanDefinitionRegistry registry) {
            BeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);
            registry.registerBeanDefinition("my",beanDefinition);
        }
    }
    

@ImportResource

用来导入传统的xml配置文件