簡介
Spring對於能夠用xml配置實現的基本都提供了註解支持,下面就經過一個實例來介紹一下怎樣使用Spring的註解來代替xml配置。java
AppConfig
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.ImportResource; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; @Configuration @EnableAspectJAutoProxy @ComponentScan(basePackages = {"cn.freemethod.spring.bean","cn.freemethod.spring.util","cn.freemethod.spring.aspectscan"}) @ImportResource("classpath:context.xml") @PropertySource(value = { "classpath:db.properties" , "classpath:dubbo.properties"},ignoreResourceNotFound = true) public class AppConfig { @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
經過xml配置文件須要一個配置文件,一樣使用註解就須要配置註解類,配置註解類使用@Configuration註解來代表這是一個配置類。 @EnableAspectJAutoProxy註解是對Aspect的註解支持。 @ComponentScan註解配置要掃描的包。 @ImportResource是導入xml配置,使註解和xml配置能夠結合使用。 @PropertySource能夠加載properties文件 @Bean是代表獲取一個實例的方法mysql
要使用@PropertySource必需要有一個PropertySourcesPlaceholderConfigurer實例,這樣就能夠在須要的地方使用@Value等註解。spring
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.AbstractApplicationContext; import cn.freemethod.spring.aspectscan.AspectS; import cn.freemethod.spring.aspectscan.DoSomething; import cn.freemethod.spring.bean.AppBean; import cn.freemethod.spring.bean.DubboBean; import cn.freemethod.spring.config.AppConfig; public class AnnotationConfigStart { public static void main(String[] args) { AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); AppBean appBean = context.getBean(AppBean.class); System.out.println(appBean); DubboBean dubboBean = context.getBean(DubboBean.class); System.out.println(dubboBean); AspectS aspectS = context.getBean(AspectS.class); System.out.println(aspectS); DoSomething doSomething = context.getBean(DoSomething.class); doSomething.doSomething(); context.close(); } }
加載xml的配置文件能夠使用一個ClassPathXmlApplicationContext類,加載註解配置能夠使用AnnotationConfigApplicationContext類。sql
測試的包的部分結構如上圖所示,其餘類請參考下面具體的類代碼,下面是測試輸出:apache
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalRequiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor appConfig org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor appBean dubboBean applicationContextProvider aspectA aspectB aspectS doSomethingImpl propertySourcesPlaceholderConfigurer xmlConfigBean org.springframework.aop.config.internalAutoProxyCreator AppBean [url=jdbc:mysql://localhost:3306/design, userName=myuser] DubboBean [appName=test, dubboProtocol=dubbo, dubboPort=20893] [cn.freemethod.spring.aspectscan.AspectA@f4d25c6, cn.freemethod.spring.aspectscan.AspectB@11eaf203] @Before @Order(2) @Before @Order(5) doSomething @After @Order(5) @After @Order(2)
aspectscan包
public interface AspectBase { }
AspectBase是一個標記接口。app
import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Component @Aspect @Order(2) public class AspectA implements AspectBase{ @Before("this(cn.freemethod.spring.aspectscan.DoSomething)") public void aspectABefore(){ System.out.println("@Before @Order(2)"); } @After("this(cn.freemethod.spring.aspectscan.DoSomething)") public void aspectAAfter(){ System.out.println("@After @Order(2)"); } }
AspectA是一個切面,使用的3個註解@Component,@Aspect,@Order(2)。@Component註解代表這是一個組件,@Aspect代表這是一個切面,@Order註解不是像不少資料解釋的是控制加載順序的。@Order標記從spring2.0出現,可是在spring4.0以前,@Order標記只支持AspectJ的切面排序。spring 4.0對@Order作了加強,它開始支持對裝載在諸如Lists和Arrays容器中的自動包裝(auto-wired)組件的排序。maven
能夠修改一下AspectA的@Order值和AspectB的@Order值的大小,觀察一下測試的輸出就能夠知道@Order的做用了。ide
import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Component @Aspect @Order(5) public class AspectB implements AspectBase{ @Before("this(cn.freemethod.spring.aspectscan.DoSomething)") public void aspectBBefore(){ System.out.println("@Before @Order(5)"); } @After("this(cn.freemethod.spring.aspectscan.DoSomething)") public void aspectAAfter(){ System.out.println("@After @Order(5)"); } }
AspectB也是一個切面,和AspectA同樣。測試
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class AspectS { @Autowired private List<AspectBase> aspects ; @Override public String toString(){ return aspects.toString(); } }
AspectS測試@Order注入List的順序。ui
public interface DoSomething { void doSomething(); }
import org.springframework.stereotype.Service; @Service public class DoSomethingImpl implements DoSomething{ public void doSomething(){ System.out.println("doSomething"); } }
上面是2個業務測試相關的接口和類,測試@Order對Aspect切面的執行順序的影響。
bean包
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class AppBean { @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String userName; @Override public String toString() { return "AppBean [url=" + url + ", userName=" + userName + "]"; } }
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class DubboBean { @Value("${app.name}") private String appName; @Value("${dubbo.protocol}") private String dubboProtocol; @Value("${dubbo.port}") private int dubboPort; public String getAppName() { return appName; } public void setAppName(String appName) { this.appName = appName; } public String getDubboProtocol() { return dubboProtocol; } public void setDubboProtocol(String dubboProtocol) { this.dubboProtocol = dubboProtocol; } public int getDubboPort() { return dubboPort; } public void setDubboPort(int dubboPort) { this.dubboPort = dubboPort; } @Override public String toString() { return "DubboBean [appName=" + appName + ", dubboProtocol=" + dubboProtocol + ", dubboPort=" + dubboPort + "]"; } }
上面2個Bean測試@PropertySource註解和@Value註解。從輸出的結果中咱們能夠看到把配置文件中的值注入到了字段中。
util
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; @Component public class ApplicationContextProvider implements ApplicationContextAware { private static ApplicationContext context; public void setApplicationContext(ApplicationContext context) throws BeansException { ApplicationContextProvider.context=context; String[] names = context.getBeanDefinitionNames(); for(String name : names){ System.out.println(name); } } public static ApplicationContext getApplicationContext() { return context; } }
ApplicationContextProvider類實現了ApplicationContextAware接口是爲了獲取ApplicationContext,能夠經過ApplicationContext獲取工廠中的類。看到有那些類被加載初始化了。
xml
public class XmlConfigBean { }
配置
context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="xmlConfigBean" class="cn.freemethod.spring.xml.XmlConfigBean" /> </beans>
db.properties
jdbc.driverClassName = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/design jdbc.username = myuser jdbc.password = mypassword
dubbo.properties
cache.path=/usr/home/test app.owner.name = test app.organization.name = freemethod app.name = test dubbo.protocol = dubbo dubbo.port=20893 dubbo.registry.address=127.0.0.1:2181 dubbo.registry.protocol=zookeeper connect.service.max.thread.threads.size =200
附錄
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.freemethod</groupId> <artifactId>config</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <spring_version>4.1.6.RELEASE</spring_version> <cglib_version>3.2.4</cglib_version> <javassist_version>3.12.1.GA</javassist_version> <junit_version>4.9</junit_version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring_version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring_version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring_version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit_version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring_version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.7.3</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.11</version> </dependency> </dependencies> </project>