问题提出
当我们在ROO中为Entity添加了@RooJavaBean
注解时,ROO会为我们自动生成了一个Region_Roo_Configurable.aj
文件,其中代码如下:
privileged aspect Region_Roo_Configurable {
declare @type: Region: @Configurable;
}
如何理解这段代码?下面一步步进行解析。
declare @type:
google了这篇文章:
AspectJ 5 supports a new kind of declare statement, declare annotation. This takes different forms according to the recipient of the annotation: declare @type for types, declare @method for methods, declare @constructor for constructors, and declare @field for fields.
可以看到,除了@type
之外还有许多形如@**
的标签。一般形式如下所示:
declare @<kind> : ElementPattern : Annotation ;
要理解这个注解的作用,首先要了解AOP中静态横切和动态横切的概念。这里有一段通俗的解释:
动态横切是通过切入点(pointcut)和链接点(joint point)在一个方面(aspect)中的创建行为的过程;方面(aspect)定义了所有的链接点,切入点以及通知(advice),以便把需要切入的职责(interweave)注入到原来的对象中;
静态横切是通过在不修改原有职责的基础上增加新的职责;以往我们用过类的继承来实现,但继承是种强依赖关系,怎么让他们松藕,这个时候我们用静态横切,用mixin;
而declare @<kind>
注解实现了静态横切的声明功能,例如:
//为data package下的所有类添加Cacheable接口
declare parents : data.* implements Cacheable
//为banking直接和间接子包下的类加上@PrivacyControlled注解
declare @type: banking..* : @PrivacyControlled;
由此可以看出declare @type: Region: @Configurable;
的意思是给所有的Region
添加了@Configurable注解。
@Configurable
google了这篇文章,里面提到:
Since spring 2
, you were writing your bean configurations to xml files. But, Spring 3 gave the freedom to move bean definitions out of xml files. Now, you can give bean definitions in your java files itself. This is called JavaConfig feature (using @Configuration annotation).
也就是说,我们可以用过@Configuration来配置bean,而不是通过xml配置文件。
假设我们有如下接口声明:
public interface DemoManager {
public String getServiceName();
}
实现如下:
public class DemoManagerImpl implements DemoManager
{
@Override
public String getServiceName()
{
return "My first service with Spring 3";
}
}
那么我们不用xml对其进行配置,用@Configuration
,如下所示:
@Configuration
public class ApplicationConfiguration {
@Bean(name="demoService")
public DemoManager helloWorld() {
return new DemoManagerImpl();
}
}
可见,@Configuration
注解声明了ApplicationConfiguration为一个配置类,@Bean(name="demoService")
可以看成是xml配置中的<bean class="**.**.ApplicationConfiguration " id="demoService"/>
。于是,我们可以这样取出bean:
</beans>
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
DemoManager obj = (DemoManager) context.getBean("demoService");
System.out.println( obj.getServiceName());
另外,@Configuration注解从属于Annotation Type Configuration这个主题下,这里有详细的介绍。
例如,可以通过
<beans>
<context:annotation-config/>
<bean class="com.acme.AppConfig"/>
</beans>
或者
<context:component-scan/>
令Configuration生效。还可以通过@Inject Environment env;
@Configuration
public class AppConfig {
@Inject Environment env;
@Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
myBean.setName(env.getProperty("bean.name"));
return myBean;
}
}
令Configuration拥有访问其他bean的能力。也可以用@Value
注解做到这一点:
@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {
@Value("${bean.name}") String beanName;
@Bean
public MyBean myBean() {
return new MyBean(beanName);
}
}
更详细的用法参考上面给出的文档
总结
综上,可以这样理解ROO的行为:@RooJavaBean
注解让ROO用declare @type: Region: @Configurable;
语句为我们的实体类添加了Configurable
特性,使我们可以直接在entity.java里面配置bean,而不用去写xml配置。