在代码中使用Spring的Annotation会给工作带来很大的便利,但这样也造成了一个问题,就是代码会被Spring的代码污染,代码会跟Spring容器绑死,代码将来不能切换使用其它容器。那能不能不用Spring自身的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类)做一下修改或提供另一个实现就可以了。