在代码中使用Spring的Annotation会给工作带来很大的便利,但这样也造成了一个问题,就是代码会被Spring的代码污染,代码会跟Spring容器绑死,代码将来不能切换使用其它容器。那能不能不用Spring自身的Annotation同时又不影响代码功能呢?方法是有的,就是使用标准的JavaEE的annotation,下面就来简单的说一说:
一、对于bean注册,一般Spring中使用如下Annotation
org.springframework.stereotype.Component @Component
org.springframework.stereotype.Repository @Repository
org.springframework.stereotype.Service @Service
org.springframework.stereotype.Controller @Controller
处理这些Annotation的类为:
org.springframework.context.annotation.ClassPathBeanDefinitionScanner
可以用如下两种来替换:
// Java EE 6:
javax.annotation.ManagedBean
// JSR-330:
javax.inject.Named
二、对于bean的注入和生命周期管理,Spring提供了对非Spring的Annotation的支持:
// JSR-250:
javax.annotation.PostConstruct
javax.annotation.PreDestroy
javax.annotation.Resource
// JAX-WS:
javax.xml.ws.WebServiceRef
// EJB 3:
javax.ejb.EJB
处理这些Annotation的类为:
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
配置方式有如下4种:
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="alwaysUseJndiLookup" value="true"/>
</bean>
<context:annotation-config />
<context:component-scan />
三、对于Bean的注入Spring也提供了对Spring自己的Annotation的支持:
org.springframework.beans.factory.annotation.Autowired @Autowired
org.springframework.beans.factory.annotation.Value @Value
处理这些Annotation的类为:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
配置方式:
<context:annotation-config />
<context:component-scan />
可以用如下两种来替换:
// JSR-330:
javax.inject.Inject @Inject
// 这个Annotation会由AutowiredAnnotationBeanPostProcessor处理
// JSR-250:
javax.annotation.Resource @Resource
// 而这个Annotation会由CommonAnnotationBeanPostProcessor处理
其中对于使用@Resource来替换@Value,需要将属性注册成singleton bean,比如在使用Spring-boot的情况下可以实现一个ApplicationContextInitializer
@SpringBootApplication(scanBasePackages = {"com.test"})
public class Application {
private static final Logger LOG = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.addInitializers(new DefaultApplicationContextInitializer());
ConfigurableApplicationContext ctx = application.run(args);
ctx.registerShutdownHook();
}
public static class DefaultApplicationContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext applicationContext) {
EnumerablePropertySource<?> ps =
(EnumerablePropertySource) applicationContext.getEnvironment().getPropertySources().get(
ConfigFileApplicationListener.APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME);
Map<String, Object> propMap = new HashMap<>();
for (String propertyName : ps.getPropertyNames()) {
propMap.put(propertyName, ps.getProperty(propertyName));
}
String info = "registerPropertyBean:";
for (String propertyName : propMap.keySet()) {
info += System.lineSeparator() + "propertyName=" + propertyName + ", propertyValue=" +
propMap.get(propertyName);
applicationContext.getBeanFactory().registerSingleton(propertyName, propMap.get(propertyName));
}
LOG.info(info);
}
}
}
@Value("${project.name}")
private String projectName;
// 可替换为
@Resource(name="project.name")
private String projectName;
四、对bean注册事务或对bean中的方法注册事务,一般Spring中使用如下Annotation
org.springframework.transaction.annotation.Transactional @Transactional
处理这些Annotation的类为:
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource
可以用如下两种来替换:
// JTA 1.2
javax.transaction.Transactional
// EJB3
javax.ejb.TransactionAttribute
经过以上几种修改后,业务代码将完全去Spring化,当需要切换使用其它容器时,只要把引导代码(比如:Application类)做一下修改或提供另一个实现就可以了。
参考文档