Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
在 Spring 框架中有很多實用的功能,不需要寫大量的配置代碼,只需添加幾個注解即可開啟。 其中一個重要原因是那些 @EnableXXX 注解,它可以讓你通過在配置類加上簡單的注解來快速地開啟諸如事務管理(@EnableTransactionManagement)、Spring MVC(@EnableWebMvc)或定時任務(@EnableScheduling)等功能。這些看起來簡單的注解語句提供了很多功能,但它們的內部機制從表面上看卻不太明顯。 一方面,對于使用者來說用這么少的代碼獲得這么多實用的功能是很好的,但另一方面,如果你不了解某個東西的內部是如何工作的,就會使調試和解決問題更加困難。
Spring 框架中那些 @EnableXXX 注解的設計目標是允許用戶用最少的代碼來開啟復雜使用的功能。 此外,用戶必須能夠使用簡單的默認值,或者允許手動配置該代碼。最后,代碼的復雜性要向框架使用者隱藏掉。 簡而言之,讓使用者設置大量的 Bean,并選擇性地配置它們,而不必知道這些 Bean 的細節(或真正被設置的內容)。下面來看看具體的幾個例子:
首先要知道的是,@EnableXXX 注解并不神奇。實際上在 BeanFactory 中并不知道這些注解的具體內容,而且在 BeanFactory 類中,核心功能和特定注解(如 @EnableWebMvc)或它們所存放的 jar 包(如 spring-web)之間沒有任何依賴關系。 讓我們看一下 @EnableScheduling,下面看看它是如何工作的。 定義一個 SchedulingConfig 配置類,如下所示:
@Configuration
@EnableScheduling
public class SchedulingConfig {
// some bean in here
}
上面的內容沒有什么特別之處。只是一個用 @EnableScheduling 注釋的標準 Java 配置。@EnableScheduling 讓你以設定的頻率執行某些方法。例如,你可以每 10 分鐘運行 BankService.transferMoneyToMghio()。 @EnableScheduling 注解源碼如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {
}
上面的 EnableScheduling 注解,我們可以看到它只是一個標準的類級注解(@Target/@Retention),應該包含在 JavaDocs 中(@Documented),但是它有一個 Spring 特有的注解(@Import)。 @Import 是將一切聯系起來的關鍵。 在這種情況下,由于我們的 SchedulingConfig 被注解為 @EnableScheduling,當 BeanFactory 解析文件時(內部是ConfigurationClassPostProcessor 在解析它),它也會發現 @Import(SchedulingConfiguration.class) 注解,它將導入該值中定義的類。 在這個注解中,就是 SchedulingConfiguration。
這里導入是什么意思呢?在這種情況下,它只是被當作另一個 Spring Bean。 SchedulingConfiguration 實際上被注解為@Configuration,所以 BeanFactory 會把它看作是另一個配置類,所有在該類中定義的 Bean 都會被拉入你的應用上下文,就像你自己定義了另一個 @Configuration 類一樣。 如果我們檢查 SchedulingConfiguration,我們可以看到它只定義了一個Bean(一個Post Processor),它負責我們上面描述的調度工作,源碼如下:
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
也許你會問,如果想配置 SchedulingConfiguration 中定義的 bean 呢? 這里也只是在處理普通的Bean。 所以你對其它 Bean 所使用的機制也適用于此。 在這種情況下,ScheduledAnnotationBeanPostProcessor 使用一個標準的 Spring Bean 生命周期(postProcessAfterInitialization)來發現應用程序上下文何時被刷新。 當符合條件時,它會檢查是否有任何 Bean 實現了 SchedulingConfigurer,如果有,就使用這些 Bean 來配置自己。 其實這一點并不明細(在 IDE 中也不太容易找到),但它與 BeanFactory 是完全分離的,而且是一個相當常見的模式,一個 Bean 被用來配置另一個 Bean。 而現在我們可以把所有的點連接起來,它(在某種程度上)很容易找到(你可以 Google 一下文檔或閱讀一下 JavaDocs)。
在上一個示例中,我們討論了像 @EnableScheduling 這樣的注解如何使用 @Import 來導入另一個 @Configuration 類并使其所有的 Bean 對你的應用程序可用(和可配置)。但是如果你想根據某些配置加載不同的 Bean 集,會發生什么呢? @EnableTransactionManagement 就是一個很好的例子。TransactioConfig 定義如下:
@Configuration
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
public class TransactioConfig {
// some bean in here
}
再一次,上面沒有什么特別之處。只是一個用@EnableTransactionManagement注釋的標準Java配置。唯一與之前的例子有些不同的是,用戶為注釋指定了一個參數(mode=AdviceMode.ASPECTJ)。 @EnableTransactionManagement注解本身看起來像這樣。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
和前面一樣,一個相當標準的注解,盡管這次它有一些參數。 然而,正如前文提到,@Import 注解是將一切聯系在一起的關鍵,這一點再次得到證實。 但區別在于,這次我們導入的是 TransactionManagementConfigurationSelector 這個類,通過源碼可以發現,其實它不是一個被 @Configuration 注解的類。 TransactionManagementConfigurationSelector 是一個實現ImportSelector 的類。 ImportSelector 的目的是讓你的代碼選擇在運行時加載哪些配置類。 它有一個方法,接收關于注解的一些元數據,并返回一個類名數組。 在這種情況下,TransactionManagementConfigurationSelector 會查看模式并根據模式返回一些類。其中的 selectImports 方法源碼如下:
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
這些類中的大多數是 @Configuration(例如 ProxyTransactionManagementConfiguration),通過前文介紹我們知道它們會像前面一樣工作。 對于 @Configuration 類,它們被加載和配置的方式與我們之前看到的完全一樣。 所以簡而言之,我們可以使用 @Import 和 @Configuration 類來加載一套標準的 Bean,或者使用 @Import 和 ImportSelector 來加載一套在運行時決定的 Bean。
@Import 支持的最后一種情況,即當你想直接處理 BeanRegistry(工廠)時。如果你需要操作Bean Factory或者在Bean定義層處理Bean,那么這種情況就適合你,它與上面的情況非常相似。 你的 AspectJProxyConfig 可能看起來像。
@Configuration
@EnableAspectJAutoProxy
public class AspectJProxyConfig {
// some bean in here
}
再一次,上面定義沒有什么特別的東西。只是一個用 @EnableAspectJAutoProxy 注釋的標準 Java 配置。 下面是@EnableAspectJAutoProxy 的源代碼。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
和前面一樣,@Import 是關鍵,但這次它指向 AspectJAutoProxyRegistrar,它既沒有 @Configuration 注解,也沒有實現 ImportSelector 接口。 這次使用的是實現了 ImportBeanDefinitionRegistrar。 這個接口提供了對 Bean 注冊中心(Bean Registry)和注解元數據的訪問,因此我們可以在運行時根據注解中的參數來操作 Bean 注冊表。 如果你仔細看過前面的示例,你可以看到我們忽略的類也是 ImportBeanDefinitionRegistrar。 在 @Configuration 類不夠用的時候,這些類會直接操作 BeanFactory。
所以現在我們已經涵蓋了 @EnableXXX 注解使用 @Import 將各種 Bean 引入你的應用上下文的所有不同方式。 它們要么直接引入一組 @Configuration 類,這些類中的所有 Bean 都被導入到你的應用上下文中。 或者它們引入一個 ImportSelector 接口實現類,在運行時選擇一組 @Configuration 類并將這些 Bean 導入到你的應用上下文中。 最后,他們引入一個ImportBeanDefinitionRegistrars,可以直接與 BeanFactory 在 BeanDefinition 級別上合作。
總的來說,個人認為這種將 Bean 導入應用上下文的方法很好,因為它使框架使用者的使用某個功能非常容易。不幸的是,它模糊了如何找到可用的選項以及如何配置它們。 此外,它沒有直接利用 IDE 的優勢,所以很難知道哪些 Bean 正在被創建(以及為什么)。 然而,現在我們知道了 @Import 注解,我們可以使用 IDE 來挖掘一下每個注解及其相關的配置類,并了解哪些 Bean 正在被創建,它們如何被添加到你的應用上下文中,以及如何配置它們。 希望對你有幫助~
文章來自https://www.cnblogs.com/mghio/p/16297637.html
Spring或Spring Boot中我們經常會用到很多@EnableXXX 注解,加上這些注解之后我們就可以 ‘啟用’ 某一個功能,或者可以使用某些Bean,比如:
@EnableAsync 使用異步執行、
@EnableTransactionManagement 啟用事務、
@EnableAutoConfiguration 開啟自動裝配
等等,那么你知道背后的原理是什么樣的嗎?本文簡要窺探一下。
無論是Spring內建的,還是我們自定義的@Enable 模塊,基本就3種實現方式,其目標都是將指定的類定位為Spring Bean:
實例1:
引導類為 @Configuration ,聲明Enable注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloworldConfiguration.class)
public @interface EnableHelloWorld {
}
@Configuration Class中定義Bean
@Configuration
public class HelloworldConfiguration {
@Bean
public String helloWorld() {
return "Hello, world";
}
}
開啟EnableHelloWorld注解,獲取 helloWorld Bean
@Configuration@EnableHelloWorldpublic class EnableHelloWorldBootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 注冊當前引導類(被@Configuration標注)到Spring上下文
context.register(EnableHelloWorldBootstrap.class);
// 啟動上下文
context.refresh();
// 獲取Bean
String helloWorld = context.getBean("helloWorld", String.class);
System.out.printf("helloWorld = %s \n", helloWorld);
// 關閉上下文
context.close();
}
}
執行結果:
helloWorld = Hello, world
實例2:導入類為 ImportSelector實現
public interface Server {
void start();
void close();
enum ServerType { HTTP, TCP }
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServerImportSelector.class)
public @interface EnableServer {
Server.ServerType type();
}
根據注解屬性,選擇要定義的Bean
public class ServerImportSelector implements ImportSelector {
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) {
Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(EnableServer.class.getName());
Server.ServerType serverType = (Server.ServerType)attributes.get("type");
String[] importClassNames = new String[0];
switch (serverType) {
case HTTP:
importClassNames = new String[]{HttpServer.class.getName()};
break;
case TCP:
importClassNames = new String[]{TcpServer.class.getName()};
break;
}
return importClassNames;
}
}
啟用Server,獲取對應的功能:
@Configuration
@EnableServer(type = Server.ServerType.TCP)
public class EnableServerBootsrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(EnableServerBootsrap.class);
context.refresh();
// 獲取Bean
Server server = context.getBean(Server.class);
// 啟用功能
server.start();
server.close();
context.close();
}
}
執行結果:
TcpServer start ...
TcpServer close ....
實例3:
導入類為 ImportBeanDefinitionRegistrar實現
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServerImportBeanDefinitionRegistrar.class)
public @interface EnableServer {
Server.ServerType type();
}
注冊Bean
public class ServerImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
ImportSelector importSelector = new ServerImportSelector(); // 篩選Class名稱集合 String[] selectedClassNames = importSelector.selectImports(importingClassMetadata); // 創建Bean定義 Stream.of(selectedClassNames)
// 轉化為BeanDefinitionBuilder對象 .map(BeanDefinitionBuilder::genericBeanDefinition)
// 轉化為BeanDefinition .map(BeanDefinitionBuilder::getBeanDefinition)
.forEach(beanDefinition -> {
// 注冊BeanDefinition到BeanDefinitionRegistry BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry); }); }
}
啟用Server,獲取對應的功能:見實例2。
Spring 內建模塊
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
}
Dubbo 內建模塊
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
}
具體實現可以看下源碼,都是相同的原理。
、創建視圖 :
CREATE VIEW [schema].[view_name] //[schema].[view_name] 視圖的名稱
--WITH ENCRYPTION, SCHEMABINDING, VIEW_METADATA
AS
///視圖需要執行的查詢語句
-- WITH CHECK OPTION
GO
2、創建索引
CREATE NONCLUSTERED INDEX index_name //NONCLUSTERED 可選參數 UNIQUE-唯一索引
ON [schema].[owner_name] ( column_name ) // [schema].[owner_name] 數據庫表 //column_name 要創建索引的列名
--WITH PAD_INDEX
-- | FILLFACTOR = fillfactor
-- | IGNORE_DUP_KEY
-- | DROP_EXISTING
-- | STATISTICS_NORECOMPUTE
-- | SORT_IN_TEMPDB, .. as required
-- ON filegroup
GO
3、查詢數據庫所有的序列
SELECT * FROM sys.sequences
4、將當前序列的值初始化到我需要的值
SELECT
NEXT VALUE FOR dbo.S_住院_床位信息表_床位ID
GO 61
5、創建索引
CREATE NONCLUSTERED INDEX index_company
ON dbo.Company (ognName,parentId,sort )
--WITH PAD_INDEX
-- | FILLFACTOR = fillfactor
-- | IGNORE_DUP_KEY
-- | DROP_EXISTING
-- | STATISTICS_NORECOMPUTE
-- | SORT_IN_TEMPDB, .. as required
-- ON filegroup
GO
CREATE NONCLUSTERED INDEX index_department
ON dbo.Department( ognName,parentId,sort,head,c_head,branched )
--WITH PAD_INDEX
-- | FILLFACTOR = fillfactor
-- | IGNORE_DUP_KEY
-- | DROP_EXISTING
-- | STATISTICS_NORECOMPUTE
-- | SORT_IN_TEMPDB, .. as required
-- ON filegroup
GO
CREATE NONCLUSTERED INDEX index_user
ON dbo.[User] (account,password,sort,name,sex )
--WITH PAD_INDEX
-- | FILLFACTOR = fillfactor
-- | IGNORE_DUP_KEY
-- | DROP_EXISTING
-- | STATISTICS_NORECOMPUTE
-- | SORT_IN_TEMPDB, .. as required
-- ON filegroup
GO
CREATE NONCLUSTERED INDEX index_userKey
ON dbo.UserKey ( userId,ognId )
--WITH PAD_INDEX
-- | FILLFACTOR = fillfactor
-- | IGNORE_DUP_KEY
-- | DROP_EXISTING
-- | STATISTICS_NORECOMPUTE
-- | SORT_IN_TEMPDB, .. as required
-- ON filegroup
GO
6、創建觸發器
---單位觸發器
CREATE TRIGGER trigger_Upate_Company
ON dbo.Company
AFTER UPDATE
AS
BEGIN
IF (SELECT enable FROM Deleted)=0
BEGIN
UPDATE dbo.Department SET enable=0 WHERE parentId IN(SELECT Deleted.ognId FROM Deleted)
END
*請認真填寫需求信息,我們會在24小時內與您取得聯系。