Spring學習之05使用註解開發

影鱷學發表於2020-11-02

使用註解開發

在spring4之後,要使用註解開發,必須保證aop的包匯入了

同時使用註解要記得匯入context約束,增加註解的支援,同時要指定要掃描的包

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--開啟註解支援-->
    <!--    <context:annotation-config/>-->
	<!--指定要掃描的包,包下的註解就會生效,使用該註解可以省略註解驅動,可以點進去註解看說明-->
    <context:component-scan base-package="com.magee.pojo"/>
</beans>

掃描類路徑以查詢將被自動註冊為Spring Bean的帶註釋的元件。預設情況下,將檢測到Spring提供的@ Component,@ Repository,@ Service,@ Controller,@ RestController,@ ControllerAdvice和@Configuration構造型。注意:此標記暗含“ annotation-config”標記的作用,在元件類中啟用@ Required,@ Autowired,@ PostConstruct,@ PreDestroy,@ Resource,@ PersistenceContext和@PersistenceUnit批註,這對於自動檢測到的元件通常是必需的(無需外部配置)。關閉’annotation-config’屬性以停用此預設行為,例如為了使用自定義BeanPostProcessor定義來處理那些註釋。注意:您可以在包路徑中使用佔位符,但只能根據系統屬性(類似於資源路徑)進行解析。元件掃描導致新的bean定義被註冊; Spring的PropertySourcesPlaceholderConfigurer將應用於這些Bean definit

將類宣告為bean:

  • @Component,
  • @Repository(資料庫層)
  • @ Service(服務層)
  • @ Controller與@ RestController(控制層)

作用域宣告使用@Scope

小結:
	xml與註解:
	1、xml功能更加萬能,使用任何場合,維護簡單方便
	2、註解使用只能在自己的類上,維護相對複雜
	xml與註解的最佳實踐:
	1、xml用來管理bean
	2、註解只負責完成屬性的注入
	3、使用的過程中記得要開啟註解支援,或開啟掃描包(包含註解開啟)

完全使用java方式來配置Spring

@Configuration和@Bean

我們現在要完全不使用Spring的xml配置,全權使用java來配置,要完全去除xml配置,我們需要java提供一個類要接替xml文件的作用

@Configuration和@Bean

@Bean的作用等價於 <bean/>標籤

@Configuration的作用等價於標註該類相當於xml文件

java配置:

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

等價的xml配置:

<beans>
    <bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

注意:完整的@Configuration與“精簡” @Bean模式?

	如果在未使用@Configuration註釋的類中宣告@Bean方法,則將它們稱為以“精簡”模式進行處理。 在@Component或什至在簡單的舊類中宣告的Bean方法被認為是“精簡版”,其中包含類的主要目的不同,而@Bean方法在那裡具有某種優勢。 例如,服務元件可以通過每個適用的元件類上的其他@Bean方法將管理檢視公開給容器。 在這種情況下,@ Bean方法是一種通用的工廠方法機制。
	
	與完整的@Configuration不同,lite @Bean方法無法宣告Bean之間的依賴關係。 取而代之的是,它們在其包含元件的內部狀態上進行操作,並根據需要宣告的引數進行操作。 因此,此類@Bean方法不應呼叫其他@Bean方法。 實際上,每個此類方法僅是用於特定bean引用的工廠方法,而沒有任何特殊的執行時語義。 這裡的積極副作用是,不必在執行時應用CGLIB子類,因此在類設計方面沒有任何限制(即,包含類可能是最終類,依此類推)。
	在常見情況下,@ Bean方法將在@Configuration類中宣告,以確保始終使用“完全”模式,並因此將跨方法引用重定向到容器的生命週期管理。 這可以防止通過常規Java呼叫意外地呼叫同一@Bean方法,這有助於減少在“精簡”模式下執行時難以追查的細微錯誤。

純註解模式下使用AnnotationConfigApplicationContext來獲取ApplicationContext

ApplicationContext context = new AnnotationConfigApplicationContext(XXX.class);
啟動元件掃描scan(String…)

要啟用元件掃描,可以按如下方式註解@Configuration類:

@Configuration
@ComponentScan(basePackages = "com.acme") 
public class AppConfig  {
    ...
}

此註解啟用元件掃描。

注意spring在沒有啟動元件掃描的情況下會自動自動掃描當前@Configuration類所在的包


@Bean的其他知識

@PostConstruct和@PreDestroy註釋。

支援常規的生命週期回撥

任何使用@Bean註釋定義的類都支援常規的生命週期回撥,並且可以使用JSR-250中的

還完全支援常規的Spring生命週期回撥。如果bean實現了InitializingBean,DisposableBean或Lifecycle,則容器將呼叫它們各自的方法。

spring還完全支援標準的* Aware介面集(例如BeanFactoryAware,BeanNameAware,MessageSourceAware,ApplicationContextAware等)。

@Bean註釋支援指定任意的初始化和銷燬回撥方法,非常類似於bean元素上Spring XML的init-method和destroy-method屬性,如以下示例所示:

public class BeanOne {

    public void init() {
        // initialization logic
    }
}

public class BeanTwo {

    public void cleanup() {
        // destruction logic
    }
}

@Configuration
public class AppConfig {

    @Bean(initMethod = "init")
    public BeanOne beanOne() {
        return new BeanOne();
    }

    @Bean(destroyMethod = "cleanup")
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

由於使用的方法的自由性,同樣可以通過使用方法內呼叫init()來返回該物件

@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        BeanOne beanOne = new BeanOne();
        beanOne.init();
        return beanOne;
    }

    // ...
}
當直接使用Java工作時,可以對物件執行任何操作,而不必總是依賴於容器生命週期,具有較大的自由性,但是使用xml配置類,對bean物件就比較固定和死板,但是維護工作比較方便
指定Bean的範圍(Scope)

使用@Scope來指定Bean的範圍,預設範圍是單例,但是您可以使用@Scope註釋覆蓋它,如以下示例所示

@Configuration
public class MyConfiguration {

    @Bean
    @Scope("prototype")
    public Encryptor encryptor() {
        // ...
    }
}
Bean命名與別名

命名使用name屬性,起多個別名使用Alias

@Configuration
public class AppConfig {

    @Bean(name = "myThing")
    public Thing thing() {
        return new Thing();
    }
}
@Configuration
public class AppConfig {

    @Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
    public DataSource dataSource() {
        // instantiate, configure and return DataSource bean...
    }
}

同時可以使用@Description註解來進一步解釋Bean的作用

@Configuration
public class AppConfig {

    @Bean
    @Description("Provides a basic example of a bean")
    public Thing thing() {
        return new Thing();
    }


@Configuration的其他知識

  • @Configuration是類級別的註釋,指示物件是Bean定義的源。

  • @Configuration類通過公共@Bean註釋方法宣告bean。

  • 對@Configuration類的@Bean方法的呼叫也可以用於定義Bean之間的依賴關係。

注入bean間的依賴關係

當bean彼此依賴時,表達這種依賴就像讓一個bean方法呼叫另一個一樣簡單,如以下示例所示:

@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        return new BeanOne(beanTwo());
    }

    @Bean
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

!!!注意僅當在@Configuration類中宣告@Bean方法時,此宣告bean間依賴關係的方法才有效。您不能使用簡單的@Component類宣告Bean間的依賴關係!!!

查詢方法注入

如前所述,查詢方法注入是一項高階功能,您應該很少使用。在單例作用域的bean依賴於原型作用域的bean的情況下,這很有用。將Java用於這種型別的配置為實現此模式提供了自然的方法。下面的示例演示如何使用查詢方法注入:

public abstract class CommandManager {
    public Object process(Object commandState) {
        // grab a new instance of the appropriate Command interface
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }

    // okay... but where is the implementation of this method?
    protected abstract Command createCommand();
}

通過使用Java配置,可以建立CommandManager的子類,在該子類中,抽象的createCommand()方法將被覆蓋,以使其查詢新的(原型)命令物件。以下示例顯示瞭如何執行此操作:

@Bean
@Scope("prototype")
public AsyncCommand asyncCommand() {
    AsyncCommand command = new AsyncCommand();
    // inject dependencies here as required
    return command;
}

@Bean
public CommandManager commandManager() {
    // return new anonymous implementation of CommandManager with createCommand()
    // overridden to return a new prototype Command object
    return new CommandManager() {
        protected Command createCommand() {
            return asyncCommand();
        }
    }
}

有條件的包含@Configuration或@Bean的方法

根據某些系統狀態,有條件地啟用或禁用完整的@Configuration類甚至單個@Bean方法通常很有用。 一個常見的示例是僅在Spring Environment中啟用特定配置檔案時才使用@Profile批註來啟用Bean。

@Profile註釋實際上是通過使用更靈活的稱為@Conditional的註釋來實現的。

Condition介面的實現提供了一個matches(…)方法,該方法返回true或false。例如,以下清單顯示了用於@Profile的實際Condition實現:

@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    // Read the @Profile annotation attributes
    MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
    if (attrs != null) {
        for (Object value : attrs.get("value")) {
            if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
                return true;
            }
        }
        return false;
    }
    return true;
}

瞭解@Conditional註解說明和使用

@Autowired、@Inject、@Value、@Resource

  • @Autowired是Spring提供的註解與JSR330一樣都是通過AutowiredAnnotationBeanPostProcessor類實現的依賴注入。

  • @inject是JSR330中的規範

  • @Resource,是JSR250規範的實現,@Resource通過CommonAnnotationBeanPostProcessor類實現依賴注入。

  • @Value通常用於注入外部屬性

Spring下的@Inject、@Autowired、@REsource註解的區別

@Value的使用案例:

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("${catalog.name}") String catalog) {
        this.catalog = catalog;
    }
}
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig { }

application.properties檔案:

catalog.name=MovieCatalog

Using @PostConstruct and @PreDestroy

CommonAnnotationBeanPostProcessor不僅可以識別@Resource註釋,還可以識別JSR-250生命週期註釋:javax.annotation.PostConstruct和javax.annotation.PreDestroy

在Spring 2.5中引入的對這些註釋的支援為初始化回撥和銷燬回撥中描述的生命週期回撥機制提供了一種替代方法。 假設CommonAnnotationBeanPostProcessor在Spring ApplicationContext中註冊,則在生命週期中與相應的Spring生命週期介面方法或顯式宣告的回撥方法在同一點呼叫帶有這些註釋之一的方法。 在以下示例中,快取在初始化時預先填充,並在銷燬時清除

public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }

    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }
}

相關文章