简介
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>