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");
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章