Spring常用注解总结

本文深入探讨Spring框架中Bean的注册方式,包括注解、FactoryBean、Import机制及条件化注册等,同时解析Bean的作用域、懒加载、生命周期管理及属性赋值策略,为开发者提供全面的Spring Bean管理指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给容器中注册组件的注解
@Controller

用在类上表明一个控制器类

@Service

用在类上表明一个Service层类

@Repository

用在类上表明一个Repository类

@Component

用在类上表明一个Bean对象,可以代替@Controller、@Service、@Repository,只是用不同的注解表明不同的业务逻辑层 语义更加清晰

@Configuration+@Bean
@Configuration
public class Conf {
	@Bean
	public Person person() {
		return new Person();
	}
}

@Configuration用在类上表明一个配置类,@Bean用在方法上,表明要注入的组件,配置类本身也会被注入到IOC中。

FactoryBean接口
public class Shape {
    private String type;

    public Shape() {
    }

    public Shape(String type) {
        this.type = type;
    }
}
public class ShapeFactoryBean implements FactoryBean<Shape> {
    @Override
    public boolean isSingleton() {
        return false;
    }

    @Override
    public Shape getObject() throws Exception {
        return new Shape();
    }

    @Override
    public Class<?> getObjectType() {
        return Shape.class;
    }
}
@Configuration
@ComponentScan(value = "com.exapmle.service.test12")
public class Conf {
    @Bean
    public ShapeFactoryBean shapeFactoryBean() {
        return new ShapeFactoryBean();
    }
}
public class test12 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(com.exapmle.service.test12.Conf.class);
        String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }

        Object shapeFactoryBean = ioc.getBean("shapeFactoryBean");
        System.out.println(shapeFactoryBean);
    }
}
//...忽略其他容器本身创建的bean
conf
shapeFactoryBean
com.exapmle.service.test12.Shape@64c87930

可以看到获取bean的名称的时候是shapeFactoryBean,但是实际的bean是Shape对象,所以getBean()的时候实际获取的是调用shapeFactoryBean对象getObject()方法创建的bean对象

那如果获取工厂bean的本身?

public class test12 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(com.exapmle.service.test12.Conf.class);
		// 给bean的名称加上&
        Object shapeFactoryBean = ioc.getBean("&shapeFactoryBean");
        // com.exapmle.service.test12.ShapeFactoryBean@64c87930
        System.out.println(shapeFactoryBean);
    }
}

可以看BeanFactory源码中,就默认给工厂bean名称加上&前缀
在这里插入图片描述

@Import
@Configuration
@Import({AAA.class, BBB.class})
public class Conf {
	@Bean
	public Person person() {
		return new Person();
	}
}

@Import用于导入第三方库中的类,因为第三方类可能并没有加注解,就用全限定类名导入。包括自定义的组件也可以用Import方式导入。组件的名称是全限定类名。

ImportSelector接口

ImportSelector的类也可以用于导入组件

/**
 * 自定义需要返回的组件
 */
public class MyImportSelector implements ImportSelector {
    /**
     * 返回导入到容器中的组件全类名
     * @param importingClassMetadata 当前标注了@Import注解的类的所有注解信息
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.exapmle.test13.Blue", "com.exapmle.test13.Red"};
    }
}
@Configuration
@Import({MyImportSelector.class})
public class Conf {

}
// 组件的名称
com.exapmle.test13.Blue
com.exapmle.test13.Red
ImportBeanDefinitionRegistrar接口

ImportBeanDefinitionRegistrar接口的功能更加多,可以自定义组件的名称,可以根据不同的条件选择要注入的bean

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param importingClassMetadata 当前类的注解信息
     * @param registry BeanDefinition注册类
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 注意这里的组件名称,如果是用Import注解导入的或者
        // 是实现了ImportSelector接口的类导入的,则应该是全限定类名作为
        // 类的名称,这里我用的是@ComponentScan+@Component导入的bean
        boolean red = registry.containsBeanDefinition("red");
        boolean blue = registry.containsBeanDefinition("blue");
        // 如果容器中已经注入了red和blue组件,则把color组件注入进去
        if(red && blue) {
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Color.class);
            registry.registerBeanDefinition("color", rootBeanDefinition);
        }
    }
}
@Configuration
@ComponentScan("com.exapmle.test13")
@Import({MyImportBeanDefinitionRegistrar.class})
public class Conf {

}
// 组件的名称
conf
blue
red
color
@Conditional+Condition接口

按照条件判断给容器中注入组件,用在类上,只有满足条件,这个类中的所有bean才能注入到IOC中,作用在方法上,只有满足条件,这个方法生成的bean才能注入到IOC中

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        assert property != null;
        if(property.contains("Linux")) {
            return true;
        }
        return false;
    }
}
public class WindowsCondition  implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        assert property != null;
        if(property.contains("Windows 10")) {
            return true;
        }
        return false;
    }
}
public class SysType {
    private String name;
    private Integer version;

    public SysType(String name, Integer version) {
        this.name = name;
        this.version = version;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", version=" + version +
                '}';
    }
}
@Configuration
public class Conf {

    @Conditional({WindowsCondition.class})
    @Bean
    public SysType sysWin() {
        return new SysType("windows", 10);
    }

    @Conditional({LinuxCondition.class})
    @Bean
    public SysType sysLinux() {
        return new SysType("linux", 5);
    }
}
public class Test14 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(com.exapmle.service.test14.Conf.class);
        ConfigurableEnvironment environment = ioc.getEnvironment();
        String os = environment.getProperty("os.name");
        System.out.println(os);
        
        String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
            
        }
    }
}

只有名称为sysWin的bean被注入到IOC中了:

Windows 10
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
conf
sysWin
指定包扫描的注解
@ComponentScan
@Configuration
@ComponentScan(value="cn.test", excludeFilters={
		@Filter(type=FilterType.ANNOTATION, classes={Controller.class, Service.class})
})

排除Controller和Service注解

@Configuration
@ComponentScan(value="cn.test", includeFilters={
		@Filter(type=FilterType.ANNOTATION, classes=
		{Controller.class, Service.class},
		useDefaultFilters=false)
})

只包含Controller和Service注解,useDefaultFilters=false表示禁用默认过滤规则,因为默认是全部扫描

@ComponentScans

用@ComponentScans指定多种包扫描规则:

@Configuration
@ComponentScans(
	value={
		@ComponentScan(value="cn.test", includeFilters={
			@Filter(type=FilterType.ANNOTATION, classes=
			{Controller.class, Service.class},
			useDefaultFilters=false)
		})
	}
)
指定Bean的作用域和懒加载
@Scope

@Scope设置bean的作用域,常用取值:prototype表明多实例的,只要在使用到类的时候才会创建,每次都会重新创建对象;singleton表明单实例的(默认的),在容器启动的时候就会创建,以后使用直接从容器中取同一个对象;request作用在web中表明同一个请求创建一个实例;session作用在web中表明同一个session创建一个实例。

@Configuration
public class Conf {
	@Bean
	@Scope("prototype")
	public Person person() {
		return new Person();
	}
}
@Lazy

@Lazy针对单实例bean的懒加载策略,只要在bean第一次使用的时候才创建,以后都用的是同一个对象

@Configuration
public class Conf {
	@Bean
	@Lazy
	public Person person() {
		return new Person();
	}
}
指定Bean的生命周期

方式一:

bean的生命周期由IOC容器管理,我们可以自定义初始化和销毁方法,由@Bean注解的initMethod 和destroyMethod指定,容器负责进行调用

public class Color {
    public void init() {
        System.out.println("Color---init");
    }
    public void destory() {
        System.out.println("Color---destory");
    }
}
@Configuration
@ComponentScan(value = "com.exapmle.service.test14")
public class Conf {
    @Bean(initMethod = "init", destroyMethod = "destory")
    public Color color() {
        return new Color();
    }
}
public class Test14 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(com.exapmle.service.test14.Conf.class);
        Object color = ioc.getBean("color");
        System.out.println(color);
        ioc.close();
    }
}
Color---init
com.exapmle.service.test14.Color@1e67a849
Color---destory

对于单实例的bean,容器关闭的时候bean就会被销毁,但是对于多实例的bean,销毁是由GC管理的

方式二:
实现InitializingBean和DisposableBean接口,有容器自动调用

public class Color implements InitializingBean, DisposableBean {
	
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean-destory");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean-afterPropertiesSet");
    }

    public void selfInit() {
        System.out.println("selfInit");
    }

    public void selfDestory() {
        System.out.println("selfDestory");
    }
}
InitializingBean-afterPropertiesSet
selfInit
com.exapmle.service.test14.Color@667a738
DisposableBean-destory
selfDestory

方式三:
JSR250提供的两个注解:@PostConstruct和@PreDestory

public class Color implements InitializingBean, DisposableBean {

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean-destory");

    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean-afterPropertiesSet");
    }

    public void selfInit() {
        System.out.println("selfInit");
    }

    public void selfDestory() {
        System.out.println("selfDestory");
    }

    @PostConstruct
    public void init2() {
        System.out.println("init2---@PostConstruct");
    }

    @PreDestroy
    public void destory2() {
        System.out.println("init2---@PreDestroy");
    }
}
init2---@PostConstruct
InitializingBean-afterPropertiesSet
selfInit
com.exapmle.service.test14.Color@400cff1a
init2---@PreDestroy
DisposableBean-destory
selfDestory
给属性赋值的注解@Value、@PropertySource
public class Person{
	@Value("张三")
	private String name;
	@Value("#{10*2}")
	private Integer age;
}
// pro.properties
person.name = "张三"
@PropertySource(value={"classpath:/pro.properties"})
@Configuration
public class Conf {
	@Bean
	@Scope("prototype")
	public Person person() {
		return new Person();
	}
}
public class Person{
	@Value("${person.name}")
	private String name;
}

@Value注解的三种用法:

  • 基本数值 @Value(“张三”)
  • SpEL表达式 @Value("#{10*2}")
  • ${}取运行环境变量中的值,结合@PropertySource注解指定配置文件的路径,读取配置文件中的键值保存到运行环境中
自动装配的注解

自动装配Spring利用DI完成对IOC容器中各个组件的依赖关系的赋值

@Autowired

@Autowired:自动按照类型注入,如何匹配上多个,再按照属性的名称名称和bean的id进行匹配。
该注解除了用在属性上,还可以作用在方法上、构造器、参数上:

@Component
public class Boss {
	Car car;
	
	// 自动获取IOC容器中的Car
	@Autowired
	public Boss(Car car) {
		this.car = car;
	}
	
	@Autowired
	public void setCar(Car car) {
		this.car = car;
	}

	public void setCar(@Autowired Car car) {
		this.car = car;
	}
}

@Autowired(required=false) // 表示如果没有找到组件,可以不装配

@Qualifier

@Qualifier:按照类型注入的基础上再按照指定的bean的id匹配,不能单独用在类的属性上(要和@Autowired注解一起使用),但是可以单独用于方法参数注入。
属性:value用于指定注入bean的id

@Primary

@Primary:这个注解不是放在属性上,而是放在配置类的打上了@Bean注解的方法上,表明如果使用@Autowired装配bean的时候,首选这个bean进行装配。

上面三个注解是Spring规范中的注解,下面这两个是Java规范的注解

@Resource

@Resource:name属性用于指定注入bean的id;type属性用于指定注入bean的类型;name和type可以同时使用,也可以单独使用,也可以都不使用,默认先按照类型注入,如果匹配上多个,再按照属性名称和bean的id进行匹配。
它的默认方式和@Autowired的方式不同的地方在于,对于@Resource方式,@Primary注解是不起作用的,他也不支持类型@Autowired中required=false的功能

@Inject

需要导入依赖,和@Autowired功能一样

Aware子接口

如果自定义组件要使用Spring容器底层的组件,比如ApplicationContext、BeanFactory,只需要让我们自定义组件实现Aware的子接口并重写方法就行,容器创建这个组件的时候,会判断这个组件是否实现了相关接口,如果是,会自动调用这个方法完成注入。

以ApplicationContextAware接口举例:

@Component
public class Color implements ApplicationContextAware {
    public ApplicationContext applicationContext;

    /**
     * 容器创建bean的时候会自动调用这个方法
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
@Profile

Spring提供的可以根据当前运行环境,动态的激活和切换一系列组件的功能。比如我们需要根据开发环境、测试环境、生成环境引入不同的数据库组件。
@Profile可以作用在方法上和类上,作用在类上,表明只有含有指定运行环境变量时,这个类才会生效。

@Configuration
@ComponentScan("com.exapmle.test13")
public class Conf {
    @Profile("blue")
    @Bean
    public Blue blue() {
        return new Blue();
    }

    @Profile("red")
    @Bean
    public Red red() {
        return new Red();
    }
}
public class Test {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(Conf.class);
        String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

当前不会注册blue和red组件,添加运行环境变量-Dspring.profiles.active=blue
在这里插入图片描述
也可以通过下面这种方式添加运行环境变量:

public class Test {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext();
        ConfigurableEnvironment environment = ioc.getEnvironment();
        environment.setActiveProfiles("blue");
        ioc.register(Conf.class);
        ioc.refresh();
        String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值