Spring 常用注解解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 常用注解解析相关的知识,希望对你有一定的参考价值。

1. 常用注解

1.1 @Configuration

@Configuration
public class MainConfig {
}

@Configuration注解表明这个类是一个配置类,该类中应该包含如何在Spring应用上下文中创建bean的细节

1.2 @ComponentScan

@Configuration
@ComponentScan("per.ym")
public class MainConfig {
}

@ComponentScan注解用于启用组件扫描,其作用同xml中配置<context:component-scan>。上述中的配置将会扫描per.ym包下的所有类,若不配置其value值,它会以配置类所在的包作为基础包(base package)来扫描组件。如果你想同时扫描多个包,可以这样配置:

@Configuration
@ComponentScan("per.ym, per.mm")
public class MainConfig {
}

在上面的例子中,所设置的基础包是以String类型表示的。我认为这是可以的,但这种方法是类型不安全(not type-safe)的。如果你重构代码的话,那么所指定的基础包可能就会出现错误了。除了将包设置为简单的String类型之外,@ComponentScan还提供了另外一种方法,那就是将其指定为包中所包含的类或接口:

@Configuration
@ComponentScan(basePackageClasses = {MyService.class,  MyDao.class})
public class MainConfig {
}

你可以考虑在包中创建一个用来进行扫描的空标记接口(marker interface)。通过标记接口的方式,你依然能够保
持对重构友好的接口引用,但是可以避免引用任何实际的应用程序代码

1.3 @Controller, @Service, @ Repository, @Component

这几个自然不用多说,算是见得最多的了,它们锁修饰的类在被spring容器扫描到时会被加入到spring的管理之中。

@Controller对应表现层的Bean

@Service对应的是业务层Bean

@Repository对应数据访问层Bean

@Component,当你不能明确的选择上述3中,就用这个

Spring应用上下文中所有的bean都会给定一个ID,如果没有明确指定,Spring会根据类名为其指定一个ID,也就是将类名的第一个字母变为小写。你也可以这样显示的指定一个ID:

@Component("ymm")
public class Person() {
}

Spring支持将@Named(Java依赖注入规范中所提供的)作为@Component注解的替代方案。两者之间有一些细微的差异,但是在大多数场景中,它们是可以互相替换的。

1.4 @Bean

@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文中
的bean。方法体中包含了最终产生bean实例的逻辑。

@Configuration
public class MainConifg {
    @Bean
    public BookDao bookDao(){
        return new BookDao();
    }
}

@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文中
的bean。方法体中包含了最终产生bean实例的逻辑。

默认情况下,bean的ID与带有@Bean注解的方法名是一样的。在上例中,bean的名字将会是bookDao。如果你想为其设置成一个不同的名字的话,那么可以重命名该方法,也可以通过name属性指定一个不同的名字:

@Configuration
public class MainConifg {
    @Bean(" ymBookDao")
    public BookDao bookDao(){
        return new BookDao();
    }
}

还可以像这样设置初始化方法和销毁方法:

@Configuration
public class MainConifg {
    @Bean(initMethod = "init", destroyMethod = "destroy")
    public BookDao bookDao(){
        return new BookDao();
    }
}

这如同在xml中配置init-method="init" destroy-method="destory"一样

1.5 @Autowired

借助@Autowired注解可以实现spring的自动装配,自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean

@Service
public class BookService {

    @Autowired(required=false)
    private BookDao bookDao;

}

你可以把@Autowired标注在属性、构造器、setter方法上。实际上,Setter方法并没有什么特殊之处,@Autowired注解甚至可以用在类的任何方法上。

除了自带的@Autowired,spring还支持Java规范中的@Resource(JSR250)和@Inject(JSR330),它们之间的区别如下:

@Autowired:

a,默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class),如果有且只有一个 bean匹配依赖需求的话,那么这个bean将会被装配进来;如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找applicationContext.getBean("bookDao");

b,@Qualifier("bookDao"):使用@Qualifier明确指定需要装配的组件的id,而不是使用属性名;

c,自动装配默认一定要将属性赋值好,没有就会报错;可以使用@Autowired(required=false);

d,@Primary:让Spring进行自动装配的时候,默认使用首选的bean;也可以使用@Qualifier指定需要装配的bean的名字;

@Resource:

a,和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;

b,不支持@Primary功能;

c,不支持required=false的功能;

@Inject:

a,和@Autowired一样实现自动装配功能;

b,不支持required=false的功能;

一个可能的例子:

@Configuration
@ComponentScan("per.ym.service")
public class MainConifgOfAutowired {

    @Primary
    @Bean("bookDao1")
    public BookDao bookDao1(){
        BookDao bookDao = new BookDao();
        bookDao.setLable("1");
        return bookDao;
    }

   @Bean("bookDao2")
   public BookDao bookDao2(){
     BookDao bookDao = new BookDao();
     bookDao.setLable("2");
     return bookDao;
   }
}   

@Service
public class BookService {

    @Qualifier("bookDao1")
    @Autowired(required=false)
    private BookDao bookDao;

    //@Resource(name="bookDao2")
    //private BookDao bookDao;

    //@Qualifier("bookDao2")
    //@Inject
    //private BookDao bookDao;
}

public class BookDao {

    private String lable = "0";

    public String getLable() {
        return lable;
    }

    public void setLable(String lable) {
        this.lable = lable;
    }
}

1.6 @Import

通过导入的方式实现快速给容器中导入组件,其上可以配置3种类型的值,分别是普通bean,ImportSelector,ImportBeanDefinitionRegistrar。特别的,你可以导入一个被@Configuration注解修饰的bean,这和在一个spring配置文件中使用<import resource="classpath*:/spring/other.xml" />引入其他配置文件时相似的

@Configuration
@Import({MainConfig2.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig {
}

MainConfig2可以是另一个配置类或者普通的bean:

@Configuration
public class MainConfig2 {

    @Bean
    public Person person(){
        return new Person();
    }
}

ImportSelector,其selectImports方法返回的数组中应包含要导入容器的bean的全类名

public class MyImportSelector implements ImportSelector {

    //返回值,就是到导入到容器中的组件全类名
    //AnnotationMetadata:当前标注@Import注解的类的所有注解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //方法不要返回null值,否则会有NPE
        return new String[]{"per.ym.bean.Car","per.ym.bean.Dog"};
    }

}

ImportBeanDefinitionRegistrar,调用BeanDefinitionRegistry.registerBeanDefinition手工注册想要添加到容器中的bean

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry:BeanDefinition注册类;
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //指定Bean定义信息
        RootBeanDefinition beanDefinition = new RootBeanDefinition(Red.class);
        //注册一个Bean,指定bean名
        registry.registerBeanDefinition("red", beanDefinition);
    }

}

1.7 @Conditional

放在类上,当满足条件时,这个类中配置的所有bean注册才能生效

放在方法上,当满足条件时,才向容器中注册当前bean

@Conditional({WindowsCondition.class})
@Configuration
public class MainConfig {

    @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person(){
        return new Person("linus");
    }
}

/**
* ConditionContext:判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata:注释信息
*/
//判断是否windows系统
public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //1、能获取到ioc使用的beanfactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

        //2、获取类加载器
        ClassLoader classLoader = context.getClassLoader();

        //3、获取到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();

        //4、获取当前环境信息
        Environment environment = context.getEnvironment();

        String property = environment.getProperty("os.name");
        if(property.contains("Windows")){
            return true;
        }

        return false;
    }

}

1.8 @Profile

根据当前环境,动态的激活和切换一系列组件的功能;指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件

加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中

写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效

@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{

    @Value("${db.user}")
    private String user;

    private StringValueResolver valueResolver;

    private String  driverClass;

    @Profile("test")
    @Bean("testDataSource")
    public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Profile("dev")
    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dev");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Profile("prod")
    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/prod");

        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.valueResolver = resolver;
        driverClass = valueResolver.resolveStringValue("${db.driverClass}");
    }

}

db.properties:

db.user=root
db.password=123456
db.driverClass=com.mysql.jdbc.Driver

启动命令行中设置环境参数:

-Dspring.profiles.active=test

代码方式设置:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
applicationContext.getEnvironment().setActiveProfiles("dev");

以上是关于Spring 常用注解解析的主要内容,如果未能解决你的问题,请参考以下文章

spring常用注解使用解析

spring常用注解使用解析

Java注解及其原理以及分析spring注解解析源码

Spring框架常用注解

spring boot常用的注解

Spring注解总结