Beajsonproperty注解解什么意思

J2EE &&&&最新内容
J2EE &&&&随机内容java注解应用 - yanbin_new - 博客园
多学习,多积累,多分享,厚积薄发。
posts - 14, comments - 64, trackbacks - 0, articles - 0
在现在项目中注解应用越来越广泛。为了有更深的理解,前面学习了java注解使用的一些原理,做了相关的总结和梳理,对注解有了更深的认识。趁热打铁,利用理解到的注解做点东西吧。结合日常工作中的一个点,利用注解做一些改造,也可以知道注解在实际项目中的用处。方便以后碰到相关情况可以利用。
废话不多说,直入正题:
一般的管理系统中,都会有定时执行的任务,一般用于按一定规律进行统计。比如日,周,月的统计,业务逻辑不需要和人为结合的。这种情况就不需要在系统中做一个模块功能让用户自己点击触发了。可以利用框架中的定时触发器来做。设定时间,到点触发执行。我们项目组中俗称:&日终&,但并不准确。还是定时器比较好。
定时器实现现在比较流行的是:spring + quartz 的框架。应用起来也比较简单:
1、定义需要定时触发的业务类;
之后就是xml中的配置。
2、包装业务类为定时器认识的类;
3、为需要定时出发的类,声明一个定时器,并声明出发时间;
4、将定时器注入到定时器的factory;
a、业务类:
* @author yanbin
public class Job1 {
public void execute() {
System.out.println("job1 say");
b、spring trigger.xml的配置
&!--1、 注入配置日终 --&
&bean id="job1" class="trigger.Job1" /&
&!--2、包装业务类为定时器类 --&
&bean id="task" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"&
&!-- 调用的类--&
&property name="targetObject"&
&ref bean="job1"/&
&/property&
&!-- 调用类中的方法 --&
&property name="targetMethod"&
&value&execute&/value&
&/property&
&!-- 3、定义触发时间 --&
&bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"&
&property name="jobDetail"&
&ref bean="task"/&
&/property&
&!-- cron定时表达式 --&
&property name="cronExpression"&
&value&0/3 * * * * ?&/value&
&/property&
&!-- 4、注入factory设置调度 --&
&bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"&
&property name="triggers"&
&ref bean="cronTrigger" /&
&/property&
这样就完成了一个定时器的实现,定时器会在spring容器启动的时候同时启动。在应用正常运行的情况下,到指定的时间调用业务类执行。
但是看了这样的一个实现方式,如果再需要配置一个定时器,job2,配置业务bean,MethodInvokingJobDetailFactoryBean,CronTriggerBean,添加到SchedulerFactoryBean。同样类似的配置。渐渐的在系统中业务复杂了,定时器需求越来越多,配置越来越多。这个trigger.xml将越来越庞大,可能会导致不好维护。
这个时候,注解就派上用场了。自己尝试了利用注解对这个实现进行改造。利用的其实还是注解的基本原理来实现(mark前文)。主要思路:
1、定义注解
2、标记业务类,执行业务方法。(使用注解)
3、从spring容器中,获取标记的业务类,业务方法。
4、继承spring的trigger解析,重写实现方法。注入到SchedulerFactoryBean中。(解析注解)
a、定义两个注解:
* 定时器标记类注解
* @author yanbin
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface TriggerType {
String value() default "";
/** 定义定时器触发时间 */
String cronExpression() default "";
* 定时器执行方法标记注解
* @author yanbin
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TriggerMethod {
String value() default "";
b、业务类使用注解:
* @author yanbin
@TriggerType(cronExpression = "0/3 * * * * ?") //指定定时时间
public class Job1 {
@TriggerMethod
public void execute() {
System.out.println("job1 say");
c、继承重写spring实现,加入解析注解
* 解析日终类
* @author yanbin
public class MySchedulerFactoryBean extends SchedulerFactoryBean {
/** 日志 */
protected Log log = LogFactory.getLog(MySchedulerFactoryBean.class.getName());
/** Spring 上下文 */
private ApplicationContext applicationC
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationC
public void registerJobsAndTriggers() throws SchedulerException {
// 获取所有bean name
String[] beanNames = applicationContext.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
Class&?& targetClass = applicationContext.getType(beanName);
// 循环判断是否标记了TriggerType注解
if (targetClass.isAnnotationPresent(TriggerType.class)) {
Object targetObject = applicationContext.getBean(beanName);
TriggerType triggerType = (TriggerType) targetClass.getAnnotation(TriggerType.class);
// 获取时间表达式
String cronExpression = triggerType.cronExpression();
String targetMethod = "";
// 确定标记了TriggerMethod注解的方法名
Method[] methods = targetClass.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(TriggerMethod.class)) {
targetMethod = method.getName();
// 注册定时器业务类
registerJobs(targetObject, targetMethod, beanName, cronExpression);
} catch (Exception e) {
log.error(e);
* 注册定时器
* @param targetObject
* @param targetMethod
* @param beanName
* @param cronExpression
* @throws Exception
private void registerJobs(Object targetObject, String targetMethod, String beanName, String cronExpression)
throws Exception {
// 声明包装业务类
MethodInvokingJobDetailFactoryBean jobDetailFactoryBean = new MethodInvokingJobDetailFactoryBean();
jobDetailFactoryBean.setTargetObject(targetObject);
jobDetailFactoryBean.setTargetMethod(targetMethod);
jobDetailFactoryBean.setBeanName(beanName);
jobDetailFactoryBean.afterPropertiesSet();
// 获取JobDetail
JobDetail jobDetail = jobDetailFactoryBean.getObject();
// 声明定时器
CronTriggerBean cronTriggerBean = new CronTriggerBean();
cronTriggerBean.setJobDetail(jobDetail);
cronTriggerBean.setCronExpression(cronExpression);
cronTriggerBean.setBeanName(beanName + "CronBean");
cronTriggerBean.afterPropertiesSet();
// 将定时器注册到factroy
List&Trigger& triggerList = new ArrayList&Trigger&();
triggerList.add(cronTriggerBean);
Trigger[] triggers = (Trigger[]) triggerList.toArray(new Trigger[triggerList.size()]);
setTriggers(triggers);
super.registerJobsAndTriggers();
d、在spring的容器xml配置文件中,将这个解析类的bean放入容器中,开始就初始化。
&!-- 自定义设置计时器调度 --&
&bean id="scheduler" class="trigger.MySchedulerFactoryBean"/&
搞定,这样就可以了,启动项目,定时器就会按时的执行。在以后如果在需要添加一个业务定时器,只需要定义类,并标注注解就行了,不需要额外的配置。维护起来只需关注定时器这个包下的类,方便维护。
水平有限,只是做这么个改造实现,可能考虑的还不够多,例如:解析类中的代码效率啊,资源损耗啊。但主要还是说明下,注解在系统中的应用。还是很多场合可以用到。任何事物都是有两面性的,注解也是有利有弊。根据自己的项目,合理利用注解。@Resource注解
@Resource 注解被用来激活一个命名资源(named
resource)的依赖注入,在JavaEE应用程序中,该注解被典型地转换为绑定于JNDI context中的一个对象。
Spring确实支持使用@Resource通过JNDI
lookup来解析对象,默认地,拥有与@Resource注解所提供名字相匹配的“bean
name(bean名字)”的Spring管理对象会被注入。
在下面的例子中,Spring会向加了注解的setter方法传递bean名为“dataSource”的Spring管理对象的引用。
@Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataS
直接使用@Resource注解一个域(field)同样是可能的。通过不暴露setter方法,代码愈发紧凑并且还提供了域不可修改的额外益处。正如下面将要证明的,@Resource注解甚至不需要一个显式的字符串值,在没有提供任何值的情况下,域名将被当作默认值。
private DataSource dataS // inject the bean named 'dataSource'
该方式被应用到setter方法的时候,默认名是从相应的属性衍生出来,换句话说,命名为'setDataSource'的方法被用来处理名为'dataSource'的属性。
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataS
当@Resource没有显式提供名字的时候,如果根据默认名字找不到对应的Spring管理对象,注入机制会回滚至类型匹配(type-match)。如果刚好只有一个Spring管理对象符合该依赖的类型,那么它会被注入。通过设置CommonAnnotationBeanPostProcessor
的‘fallbackToDefaultTypeMatch’属性为“false”(默认值是“true”)可以禁用这一特性。
&bean class="org.springframework.monAnnotationBeanPostProcessor"&
&property name="fallbackToDefaultTypeMatch" value="false"/&
正如上文所提到的,在解析标有@Resource注解的依赖时,Spring支持JNDI-lookup。如若要强制对所有使用@Resource注解的依赖进行JNDI
lookup,那也只要将CommonAnnotationBeanPostProcessor的'alwaysUseJndiLookup'
标识设置为true就可以了(默认值是false)。
&bean class="org.springframework.monAnnotationBeanPostProcessor"&
&property name="alwaysUseJndiLookup" value="true"/&
另一个选择是,激活指定为‘resource-ref-mappings’的依据全局JNDI名的查找,在@Resource注解内提供‘mappedName’属性。即使目标对象实际上是一个JNDI资源,仍然推荐引入一个Spring管理对象,这样可以提供一个间接层并且因此降低耦合程度。自Spring2.0开始添加命名空间以来,定义一个委托Spring处理JNDI
lookup的bean也变得愈发简练:
&jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/&
这个方法的优点在于间接层带来了巨大的部署弹性。比如说,一个单独的系统测试环境应该不再需要JNDI注册。在这种情况下,在系统测试配置中可以提供如下的bean定义:
&bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/&
顺便提一下,上面的例子中,实际的JDBC连接属性从一个属性文件(properties
file)解析而来,在这个属性文件里,关键字与提供的${占位符}互相对应,这需要注册一个名为PropertyPlaceholderConfigurer的BeanFactoryPostProcessor实现来完成。这是具体化那些属性(通常是针对特定环境的属性)常用的技术,这些属性可能比其他配置修改得更为频繁。
&bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&
&property name="location" value="classpath:jdbc.properties"/&
Srping2.5中新加入了‘context’命名空间,这个命名空间让我们能够得到更为简洁的方式来实现属性占位符(property
placeholder)的配置:
&context:property-placeholder location="classpath:jdbc.properties"/&
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。& Spring框架学习【解析和注入注解配置的资源】
Spring框架学习【解析和注入注解配置的资源】
1.类内部的注解,如:@Autowire、@Value、@Required、@Resource以及EJB和WebSerivce相关的注解,是容器对Bean对象实例化和依赖注入时,通过容器中注册的Bean后置处理器处理这些注解的。
2.Spring中处理注解的Bean后置处理器:
当使用Spring的注解功能时,在Spring配置文件中添加如下配置开启Spring的注解处理器:
[xhtml] view plaincopy
&context:annotation-config&
& context:component-scan &
上面的配置将隐式地向Spring容器注册、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor以及这4个专门用于处理注解的Bean后置处理器。
下面将具体介绍这4个注解后置处理器。
是Spring容器专门处理配置了自动依赖注入装配相关注解(@Autowire、@Value以及其他JSR-330注解)的Bean后置处理器,其主要功能源码如下:
(1).的构造方法:
AutowiredAnnotationBeanPostProcessor只有一个的构造方法,其源码如下:
[java] view plaincopy
public AutowiredAnnotationBeanPostProcessor() {
//后置处理器将处理@Autowire注解
this.autowiredAnnotationTypes.add(Autowired.class);
//后置处理器将处理@Value注解
this.autowiredAnnotationTypes.add(Value.class);
//获取当前类的类加载器
ClassLoader cl = AutowiredAnnotationBeanPostProcessor.class.getClassLoader();
//后置处理器将处理javax.inject.Inject JSR-330注解
this.autowiredAnnotationTypes.add((Class&? extends Annotation&) cl.loadClass("javax.inject.Inject"));
("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
(2).为指定类选择其合适的构造方法:
容器对指定类进行自动依赖注入装配(autowiring)时,容器需要对Bean调用合适的构造方法创建实例对象,AutowiredAnnotationBeanPostProcessor为指定类选择相应的构造方法,源码如下:
[java] view plaincopy
//为自动依赖注入装配Bean选择合适的构造方法
public Constructor[] determineCandidateConstructors(Class beanClass, String beanName) throws BeansException {
//首先从容器的缓存中查找是否有指定Bean的构造方法
Constructor[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
//容器缓存中没有给定类的构造方法
if (candidateConstructors == null) {
//线程同步以确保容器中数据一致性
synchronized (this.candidateConstructorsCache) {
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
//通过JDK反射机制,获取指定类的中所有声明的构造方法
Constructor[] rawCandidates = beanClass.getDeclaredConstructors();
//存放候选构造方法的集合
List&Constructor& candidates = new ArrayList&Constructor&(rawCandidates.length);
//autowire注解中required属性指定的构造方法
Constructor requiredConstructor =
//默认的构造方法
Constructor defaultConstructor =
//遍历所有的构造方法,检查是否添加了autowire注解,以及是否
//指定了required属性
for (Constructor&?& candidate : rawCandidates) {
//获取指定类中所有关于autowire的注解(Annotation)
Annotation annotation = findAutowiredAnnotation(candidate);
//如果指定类中有关于antowire的注解
if (annotation != null) {
//如果antowire注解中指定了required属性
if (requiredConstructor != null) {
throw new BeanCreationException("Invalid autowire-marked constructor: " + candidate +
". Found another constructor with 'required' Autowired annotation: " +
requiredConstructor);
//如果autowire注解的参数列表为空
if (candidate.getParameterTypes().length == 0) {
throw new IllegalStateException(
"Autowired annotation requires at least one argument: " + candidate);
//获取autowire注解中required属性值
boolean required = determineRequiredStatus(annotation);
//如果获取到autowire注解中required的属性值
if (required) {
//如果候选构造方法集合不为空
if (!candidates.isEmpty()) {
throw new BeanCreationException(
"Invalid autowire-marked constructors: " + candidates +
". Found another constructor with 'required' Autowired annotation: " +
requiredConstructor);
//当前的构造方法就是required属性所配置的构造方法
requiredConstructor =
//将当前的构造方法添加到哦啊候选构造方法集合中
candidates.add(candidate);
//如果类中没有autowire的相关注解,并且构造方法参数列表为空
else if (candidate.getParameterTypes().length == 0) {
//当前的构造方法是默认构造方法
defaultConstructor =
//如果候选构造方法集合不为空
if (!candidates.isEmpty()) {
//如果所有的构造方法都没有配置required属性,且有默认构造方法
if (requiredConstructor == null && defaultConstructor != null) {
//将默认构造方法添加到候选构造方法列表
candidates.add(defaultConstructor);
//将候选构造方法集合转换为数组
candidateConstructors = candidates.toArray(new Constructor[candidates.size()]);
//如果候选构造方法集合为空,则创建一个空的数组
candidateConstructors = new Constructor[0];
//将类的候选构造方法集合存放到容器的缓存中
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
//返回指定类的候选构造方法数组,如果没有返回null
return (candidateConstructors.length & 0 ? candidateConstructors : null);
(3).AutowiredAnnotationBeanPostProcessor对方法和属性的依赖注入:
当Spring容器对配置了autowire相关注解的Bean进行依赖注入时,后置处理器对属性和对象进行自动注入处理,源码如下:
[java] view plaincopy
//处理类中的属性
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
//获取指定类中autowire相关注解的元信息
InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());
//对Bean的属性进行自动注入
metadata.inject(bean, beanName, pvs);
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
//处理对象的注入
public void processInjection(Object bean) throws BeansException {
//获取给定Bean的Class对象
Class&?& clazz = bean.getClass();
//获取给定类中autowire相关注解元信息
InjectionMetadata metadata = findAutowiringMetadata(clazz);
//对Bean对象进行自动注入
metadata.inject(bean, null, null);
catch (Throwable ex) {
throw new BeanCreationException("Injection of autowired dependencies failed for class [" + clazz + "]", ex);
//获取给定类的autowire相关注解元信息
private InjectionMetadata findAutowiringMetadata(Class clazz) {
//首先从容器中查找是否有给定类的autowire相关注解元信息
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
if (metadata == null) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(clazz);
if (metadata == null) {
//解析给定类autowire相关注解元信息
metadata = buildAutowiringMetadata(clazz);
//将得到的给定类autowire相关注解元信息存储在容器缓存中
this.injectionMetadataCache.put(clazz, metadata);
//解析给定类autowire相关注解元信息
private InjectionMetadata buildAutowiringMetadata(Class clazz) {
//创建一个存放注解元信息的集合
LinkedList&InjectionMetadata.InjectedElement& elements = new LinkedList&InjectionMetadata.InjectedElement&();
Class&?& targetClass =
//递归遍历当前类及其所有基类,解析全部注解元信息
//创建一个存储当前正在处理类注解元信息的集合
LinkedList&InjectionMetadata.InjectedElement& currElements = new LinkedList&InjectionMetadata.InjectedElement&();
//利用JDK反射机制获取给定类中所有的声明字段,获取字段上的注解信息
for (Field field : targetClass.getDeclaredFields()) {
//获取给定字段上的注解
Annotation annotation = findAutowiredAnnotation(field);
if (annotation != null) {
//如果给定字段是静态的(Static),则直接遍历下一个字段
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
//判断注解的required属性值是否有效
boolean required = determineRequiredStatus(annotation);
//将当前字段元信息封装,添加在返回的集合中
currElements.add(new AutowiredFieldElement(field, required));
//利用JDK反射机制获取给定类中所有的声明方法,获取方法上的注解信息
for (Method method : targetClass.getDeclaredMethods()) {
//获取给定方法上的所有注解
Annotation annotation = findAutowiredAnnotation(method);
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
//如果方法是静态的,则直接遍历下一个方法
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
//如果方法的参数列表为空
if (method.getParameterTypes().length == 0) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation should be used on methods with actual parameters: " + method);
//判断注解的required属性值是否有效
boolean required = determineRequiredStatus(annotation);
//获取当前方法的属性描述符,即方法是可读的(readable)getter方法,
//还是可写的(writeable)setter方法
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
//将方法元信息封装添加到返回的元信息集合中
currElements.add(new AutowiredMethodElement(method, required, pd));
//将当前类的注解元信息存放到注解元信息集合中
elements.addAll(0, currElements);
//获取给定类的父类
targetClass = targetClass.getSuperclass();
//如果给定类有基类,并且基类不是Object,则递归获取其基类的元信息
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
//获取给定对象的autowire相关注解
private Annotation findAutowiredAnnotation(AccessibleObject ao) {
//遍历所有autowire相关的注解:@Autowire、@Value以及JSR-330等
for (Class&? extends Annotation& type : this.autowiredAnnotationTypes) {
//获取给定对象上的指定类型的注解
Annotation annotation = ao.getAnnotation(type);
if (annotation != null) {
(4).AutowiredAnnotationBeanPostProcessor对字段和方法的注入:
a.AutowiredAnnotationBeanPostProcessor对字段的注入是通过AutowiredFieldElement类的inject方法实现的,源码如下:
[java] view plaincopy
//对字段进行注入
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
//获取注入元素对象
Field field = (Field) this.
//如果当前对象在容器中被缓存
if (this.cached) {
//根据Bean名称解析缓存中的字段值
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
//如果当前对象没有被容器缓存
//创建一个字段依赖描述符
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
Set&String& autowiredBeanNames = new LinkedHashSet&String&(1);
//获取容器中的类型转换器
TypeConverter typeConverter = beanFactory.getTypeConverter();
//根据容器中Bean定义,解析指定的依赖关系,获取依赖对象
value = beanFactory.resolveDependency(descriptor, beanName, autowiredBeanNames, typeConverter);
//线程同步,确保容器中数据一致性
synchronized (this) {
//如果当前对象没有被容器缓存
if (!this.cached) {
//获取到了当前对象的依赖对象,并且required属性为true
if (value != null || this.required) {
this.cachedFieldValue =
//为指定Bean注册依赖Bean
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
//如果容器中有指定名称的Bean对象
if (beanFactory.containsBean(autowiredBeanName)) {
//依赖对象类型和字段类型匹配,默认按类型注入
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
//创建一个依赖对象的引用,同时缓存
this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName);
//如果获取的依赖关系为null,且获取required属性为false
//将字段值的缓存设置为null
this.cachedFieldValue =
//容器已经对当前字段的值缓存
this.cached =
//如果字段依赖值不为null
if (value != null) {
//显式使用JDK的反射机制,设置自动的访问控制权限为允许访问
ReflectionUtils.makeAccessible(field);
//为Bean对象的字段设置值
field.set(bean, value);
catch (Throwable ex) {
throw new BeanCreationException("Could not autowire field: " + field, ex);
b.AutowiredAnnotationBeanPostProcessor对字段的注入是通过AutowiredMethodElement类的inject方法实现的,源码如下:
[java] view plaincopy
//对方法进行注入
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
//如果属性被显式设置为skip,则不进行注入
if (checkPropertySkipping(pvs)) {
//获取注入元素对象
Method method = (Method) this.
//如果容器对当前方法缓存
if (this.cached) {
//获取缓存中指定Bean名称的方法参数
arguments = resolveCachedArguments(beanName);
//如果没有缓存
//获取方法的参数列表
Class[] paramTypes = method.getParameterTypes();
//创建一个存放方法参数的数组
arguments = new Object[paramTypes.length];
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
Set&String& autowiredBeanNames = new LinkedHashSet&String&(paramTypes.length);
//获取容器的类型转换器
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i & arguments. i++) {
//创建方法参数对象
MethodParameter methodParam = new MethodParameter(method, i);
//解析方法的输入参数和返回值类型
GenericTypeResolver.resolveParameterType(methodParam, bean.getClass());
//为方法参数创建依赖描述符
descriptors[i] = new DependencyDescriptor(methodParam, this.required);
//根据容器中Bean定义解析依赖关系,获取方法参数依赖对象
arguments[i] = beanFactory.resolveDependency(
descriptors[i], beanName, autowiredBeanNames, typeConverter);
//如果容器解析的方法参数为null,且方法required属性为false
if (arguments[i] == null && !this.required) {
//设置方法的参数列表为null
arguments =
//线程同步,以确保容器中数据一致性
synchronized (this) {
//如果当前方法没有被容器缓存
if (!this.cached) {
//如果方法的参数列表不为空
if (arguments != null) {
//为容器中缓存方法参数的对象赋值
this.cachedMethodArguments = new Object[arguments.length];
for (int i = 0; i & arguments. i++) {
this.cachedMethodArguments[i] = descriptors[i];
//为指定Bean注册依赖Bean
registerDependentBeans(beanName, autowiredBeanNames);
//如果依赖对象集合大小等于方法参数个数
if (autowiredBeanNames.size() == paramTypes.length) {
Iterator&String& it = autowiredBeanNames.iterator();
//为方法参数设置依赖对象
for (int i = 0; i & paramTypes. i++) {
String autowiredBeanName = it.next();
//如果容器中存在指定名称的Bean对象
if (beanFactory.containsBean(autowiredBeanName)) {
//如果参数类型和依赖对象类型匹配
if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
//创建一个依赖对象的引用,复制给方法相应的参数
this.cachedMethodArguments[i] = new RuntimeBeanReference(autowiredBeanName);
//如果方法参数列表为null,则设置容器对该方法参数的缓存为null
this.cachedMethodArguments =
//设置容器已经对该方法缓存
this.cached =
//如果方法参数依赖对象不为null
if (arguments != null) {
//使用JDK的反射机制,显式设置方法的访问控制权限为允许访问
ReflectionUtils.makeAccessible(method);
//调用Bean的指定方法
method.invoke(bean, arguments);
catch (InvocationTargetException ex) {
throw ex.getTargetException();
catch (Throwable ex) {
throw new BeanCreationException("Could not autowire method: " + method, ex);
beanFactory.resolveDependency和registerDependentBeans方法我们在Spring容器依赖注入源码分析中已经分析过,这里就不再具体分析。
后置处理器主要解析autowire相关的注解,即@Autowire、@Value等。
CommonAnnotationBeanPostProcessor是Spring中用于处理JavaEE5中常用注解(主要是EJB相关的注解)和Java6中关于JAX-WS相关的注解,可以处理PostConstruct、@PreDestroy等Bean生命周期相关事件的注解,该后置处理最核心的是处理@Resource注解,同时还可以处理JAX-WS相关的注解,按照其主要功能分析其主要实现源码:
(1).静态初始化块和构造函数:
[java] view plaincopy
//WebService关于JAX-WS的相关注解
private static Class&? extends Annotation& webServiceRefClass =
//EJB相关的注解
private static Class&? extends Annotation& ejbRefClass =
//静态初始化块
//获取当前类的类加载器
ClassLoader cl = CommonAnnotationBeanPostProcessor.class.getClassLoader();
//使用类加载器加载WebService相关的类
webServiceRefClass = (Class) cl.loadClass("javax.xml.ws.WebServiceRef");
catch (ClassNotFoundException ex) {
webServiceRefClass =
//使用类加载器加载EJB相关的类
ejbRefClass = (Class) cl.loadClass("javax.ejb.EJB");
catch (ClassNotFoundException ex) {
ejbRefClass =
//构造方法
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
//设置初始的注解类型为@PostConstruct
setInitAnnotationType(PostConstruct.class);
//设置消耗的注解为@ PreDestroy
setDestroyAnnotationType(PreDestroy.class);
//当使用@Resource注解时,忽略JAX-WS的资源类型
ignoreResourceType("javax.xml.ws.WebServiceContext");
从CommonAnnotationBeanPostProcessor的静态初始化块和构造方法可以看出该后置处理器主要处理EJB和WebService相关的注解,以及Bean生命周期事件的相关注解。
(2).CommonAnnotationBeanPostProcessor对属性值的查找:
CommonAnnotationBeanPostProcessor对普通属性的处理与AutowiredAnnotationBeanPostProcessor的处理基本相同,不同在于查找属性值的方法不同,通过autowire相关注解的required配置获取依赖的属性值,则通过对@Resource注解的解析获取属性的值,CommonAnnotationBeanPostProcessor获取属性值的主要源码:
[java] view plaincopy
//处理属性值
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
//获取@Resource注解中配置的属性值元数据
InjectionMetadata metadata = findResourceMetadata(bean.getClass());
//注入属性值,与AutowiredAnnotationBeanPostProcessor中处理相同
metadata.inject(bean, beanName, pvs);
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
//获取@Resource注解中配置的属性值元数据
private InjectionMetadata findResourceMetadata(final Class clazz) {
//首先从容器缓存中查找
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
//缓存中没有给定类的注解元信息数据
if (metadata == null) {
//线程同步,以确保容器中数据一致
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(clazz);
if (metadata == null) {
//创建一个用于存放注解元数据的集合
LinkedList&InjectionMetadata.InjectedElement& elements = new LinkedList&InjectionMetadata.InjectedElement&();
Class&?& targetClass =
//递归地的解析给定类及其所有基类的注解元信息
//创建一个存放当前类注解元数据的集合
LinkedList&InjectionMetadata.InjectedElement& currElements = new LinkedList&InjectionMetadata.InjectedElement&();
//遍历给定类中所有的字段,查找符合的注解
for (Field field : targetClass.getDeclaredFields()) {
//如果字段上配置了WebService相关的注解
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
//如果字段是静态的,则注解对静态字段无效
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
//如果字段不是静态,则将当前字段封装为WebService引用元素
currElements.add(new WebServiceRefElement(field, null));
//如果当前字段上配置了EJB相关的注解
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
//将当前字段封装为EJB引用元素
currElements.add(new EjbRefElement(field, null));
//如果当前字段上配置了@Resource注解
else if (field.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
//如果当前自动的类型不再被忽略的Resource类型中,
//则将当前字段封装为资源元素
if (!ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, null));
//遍历给定类中的所有方法,查找相关的注解
for (Method method : targetClass.getDeclaredMethods()) {
//如果方法上配置了WebService相关的注解
if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass) &&
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
//如方法是静态的,则注解不支持静态方法
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
//如果方法参数个数不等于1
if (method.getParameterTypes().length != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
//获取方法的属性描述
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
//将当前方法对象和方法属性描述封装为WebService引用元素
currElements.add(new WebServiceRefElement(method, pd));
//如果方法上配置了EJB相关的注解
else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass) &&
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
if (method.getParameterTypes().length != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
currElements.add(new EjbRefElement(method, pd));
//如果方法上配置了@Resource注解
else if (method.isAnnotationPresent(Resource.class) &&
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
currElements.add(new ResourceElement(method, pd));
//将当前类注解元信息存放到注解元信息集合中
elements.addAll(0, currElements);
//获取当前对象的基类
targetClass = targetClass.getSuperclass();
//如果基类不为null,且基类不是Object
while (targetClass != null && targetClass != Object.class);
metadata = new InjectionMetadata(clazz, elements);
//缓存给定类的注解元信息
this.injectionMetadataCache.put(clazz, metadata);
从上面的源码中,我们可以看到,对于方法上面的注解,EJB和WebService相关注解以及@Resource只能在单个参数的方法上配置,否则会有异常抛出。
(3).根据给定名称或者类型获取资源对象:
WebService和EJB相关注解以及@Resource主要是为所添加的字段或者方法注入所需要的资源,CommonAnnotationBeanPostProcessor类中获取资源的源码如下:
[java] view plaincopy
//根据给定名称或者类型获取资源对象
protected Object getResource(LookupElement element, String requestingBeanName) throws BeansException {
//如果注解对象元素的mappedName属性不为空
if (StringUtils.hasLength(element.mappedName)) {
//根据JNDI名称和类型去Spring的JNDI容器中获取Bean
return this.jndiFactory.getBean(element.mappedName, element.lookupType);
//如果该后置处理器的alwaysUseJndiLookup属性值为true
if (this.alwaysUseJndiLookup) {
//从Spring的JNDI容器中查找指定JDNI名称和类型的Bean
return this.jndiFactory.getBean(element.name, element.lookupType);
if (this.resourceFactory == null) {
throw new NoSuchBeanDefinitionException(element.lookupType,
"No resource factory configured - specify the 'resourceFactory' property");
//使用autowiring自动依赖注入装配,通过给定的名称和类型从资源容器获取Bean对象
return autowireResource(this.resourceFactory, element, requestingBeanName);
//自动依赖注入装配资源对象
protected Object autowireResource(BeanFactory factory, LookupElement element, String requestingBeanName)
throws BeansException {
Set&String& autowiredBeanN
String name = element.
if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet&String&();
//根据容器中Bean定义解析给定的依赖关系,将依赖以资源对象返回
resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
//根据给定JDNI名称和类型从Spring的JDNI容器查找资源
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
//为指定的Bean注册依赖的Bean
if (factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory)
for (String autowiredBeanName : autowiredBeanNames) {
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
(4).@Resource、WebService和EJB相关注解的解析和属性注入:
Spring中,@Resource注解是由类解析的,WebService相关注解是由类解析的,EJB相关注解是由EjbRefElement类解析的,下面就具体分析其解析的实现
a.ResourceElement解析@Resource注解和属性注入:
ResourceElement是Spring中用于解析@Resource注解和属性注入的类,源码如下:
[java] view plaincopy
//解析@Resource注解
protected void initAnnotation(AnnotatedElement ae) {
//获取元素对象的@Resource注解
Resource resource = ae.getAnnotation(Resource.class);
//获取@Resource注解的name属性值作为资源名称
String resourceName = resource.name();
//获取@Resource注解的type属性值作为资源类型
Class resourceType = resource.type();
//根据注解配置的资源名称是否为空,判断元素是否有默认名称
this.isDefaultName = !StringUtils.hasLength(resourceName);
//如果元素有默认名称
if (this.isDefaultName) {
//获取元素对象名称作为资源名称
resourceName = this.member.getName();
//如果当前添加注解的对象是方法,且方法名称以set开头,且属性名称
//不为空(方法名长度大于3,即除了set之外还有其他字符)
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() & 3) {
//利用JDK的内省机制格式化对象名称,转换为Java标准的驼峰命名法
resourceName = Introspector.decapitalize(resourceName.substring(3));
//如果当前的容器是ConfigurableBeanFactory类型容器
else if (beanFactory instanceof ConfigurableBeanFactory){
//解析给定的对象名的内嵌值做为资源名称
resourceName = ((ConfigurableBeanFactory) beanFactory).resolveEmbeddedValue(resourceName);
//如果注解配置的资源类型不为空,且不说Object类型
if (resourceType != null && !Object.class.equals(resourceType)) {
//检查资源类型是字段还是方法
checkResourceType(resourceType);
//如果注解中没有配置资源类型,则利用JDK反射机制判断是字段还是方法
resourceType = getResourceType();
//设置当前注解元素的资源名称
this.name = resourceN
//设置当前注解元素的JNDI类型
this.lookupType = resourceT
//获取@Resource注解的mappedName属性值,设置当前注解元素的JNDI名称
this.mappedName = resource.mappedName();
//获取@Resource注解的shareable属性值,设置当前注解元素是否在容器中共享
this.shareable = resource.shareable();
//注入属性
protected Object getResourceToInject(Object target, String requestingBeanName) {
//调用我们在(3)中分析的源码,注入依赖的资源对象
return getResource(this, requestingBeanName);
解析WebService相关的注解和属性注入:
WebServiceRefElement是Spring中用于解析WebService相关注解和属性注入的类,源码如下:
[java] view plaincopy
//解析WebService相关的注解
protected void initAnnotation(AnnotatedElement ae) {
//获取元素对象上的@WebServiceRef注解
WebServiceRef resource = ae.getAnnotation(WebServiceRef.class);
//获取@WebServiceRef注解的name属性值作为资源名称
String resourceName = resource.name();
//获取@WebServiceRef注解的type属性值作为资源类型
Class resourceType = resource.type();
//根据资源名称是否为空判断当前元素是否有默认名称
this.isDefaultName = !StringUtils.hasLength(resourceName);
//如果当前元素有默认名称
if (this.isDefaultName) {
//获取当前元素对象的名称作用资源名称
resourceName = this.member.getName();
//如果添加注解的当前元素是方法,且方法名以set开头,且资源对象名称不为空
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() & 3) {
//利用JDK的内省机制,将格式化资源名称(将去掉set之后的名称首字//母小写),是资源名称符合java变量的驼峰命名规则
resourceName = Introspector.decapitalize(resourceName.substring(3));
//如果@WebServiceRef注解的type属性值不为空
if (resourceType != null && !Object.class.equals(resourceType)) {
//根据注解配置的资源类型值检查资源对象是字段还是方法
checkResourceType(resourceType);
//如果@WebServiceRef注解没有配置type属性
//容器通过JDK的反射机制检查资源对象是字段还是方法类型
resourceType = getResourceType();
//将资源名称赋值给元素的名称
this.name = resourceN
//为元素设置资源类型
this.elementType = resourceT
//指定类型的资源可以Service被访问
if (Service.class.isAssignableFrom(resourceType)) {
//设置JNDI的类型
this.lookupType = resourceT
//如果指定类型的资源不能被Service访问
//根据@WebServiceRef注解的value属性值是否是Object,设置JNDI类型
this.lookupType = (!Object.class.equals(resource.value()) ? resource.value() : Service.class);
//获取@WebServiceRef注解的mappedName属性值,设置JNDI名称
this.mappedName = resource.mappedName();
//获取@WebServiceRef注解的wsdlLocation属性值,设置元素的wsdl路径
this.wsdlLocation = resource.wsdlLocation();
//属性注入
protected Object getResourceToInject(Object target, String requestingBeanName) {
//根据JNDI名称和类型获取指定资源对象
service = (Service) getResource(this, requestingBeanName);
catch (NoSuchBeanDefinitionException notFound) {
//如果JNDI类型是Service
if (Service.class.equals(this.lookupType)) {
throw new IllegalStateException("No resource with name '" + this.name + "' found in context, " +
"and no specific JAX-WS Service subclass specified. The typical solution is to either specify " +
"a LocalJaxWsServiceFactoryBean with the given name or to specify the (generated) Service " +
"subclass as @WebServiceRef(...) value.");
//如果元素的wsdl路径不为空
if (StringUtils.hasLength(this.wsdlLocation)) {
//根据wsdl获取构造方法
Constructor ctor = this.lookupType.getConstructor(new Class[] {URL.class, QName.class});
//获取元素JDNI类型的@WebServiceClient注解,创建WebService客户端对象
WebServiceClient clientAnn = this.lookupType.getAnnotation(WebServiceClient.class);
if (clientAnn == null) {
throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() +
"] does not carry a WebServiceClient annotation");
//根据构造方法和wsdl文件WebService实例对象
service = (Service) BeanUtils.instantiateClass(ctor,
new URL(this.wsdlLocation), new QName(clientAnn.targetNamespace(), clientAnn.name()));
catch (NoSuchMethodException ex) {
throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() +
"] does not have a (URL, QName) constructor. Cannot apply specified WSDL location [" +
this.wsdlLocation + "].");
catch (MalformedURLException ex) {
throw new IllegalArgumentException(
"Specified WSDL location [" + this.wsdlLocation + "] isn't a valid URL");
//如果元素没有配置wsdl文件路径,则根据JNDI类型创建WebService实例
//通过JDK的反射机制,调用合适的构造方法创建实例对象
service = (Service) BeanUtils.instantiateClass(this.lookupType);
//根据资源类型创建WebService提供服务的代理对象
return service.getPort(this.elementType);
通过上面的源码分析,我们知道Spring容器在对WebSerice进行注入时,首先通过JNDI查找容器中的实例对象,如果没有找到,则根据wsdl文件实例化WebService对象,如果没有指定wsdl文件的路径,则根据类型利用JDK的反射机制生成WebService实例对象,完成注入。
c.EjbRefElement解析EJB相关的注解和属性注入:
EjbRefElement是Spring中用于解析EJB相关注解和属性注入的类,源码如下:
[java] view plaincopy
//解析EJB相关的注解
protected void initAnnotation(AnnotatedElement ae) {
//获取元素上的@EJB注解
EJB resource = ae.getAnnotation(EJB.class);
//获取@EJB注解的beanName属性值,作为资源Bean名称
String resourceBeanName = resource.beanName();
//获取@EJB注解的name属性值,作为资源名称
String resourceName = resource.name();
//根据资源名称是否为空判断元素是否有默认名称
this.isDefaultName = !StringUtils.hasLength(resourceName);
//如果元素有默认名称
if (this.isDefaultName) {
//获取元素对象名称作用资源名称
resourceName = this.member.getName();
//如果元素是方法,且是以set开头的方法,并且元素名称不为空
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() & 3) {
//利用JDK内省机制格式化资源名称
resourceName = Introspector.decapitalize(resourceName.substring(3));
//获取@EJB注解中的beanInterface属性值,作用资源类型
Class resourceType = resource.beanInterface();
//如果资源类型不为空,且不是Object
if (resourceType != null && !Object.class.equals(resourceType)) {
//根据资源类型判断资源是字段还是方法
checkResourceType(resourceType);
//如果@EJB注解中没有指定资源类型
//利用JDK反射机制判断资源是字段还是方法类型
resourceType = getResourceType();
//设置元素的Bean名称为@EJB注解中配置的resourceBeanName属性值
this.beanName = resourceBeanN
//设置元素名称为资源名称
this.name = resourceN
//设置JNDI类型为资源类型
this.lookupType = resourceT
//获取@EJB注解中的mappedName属性值,作为JDNI名称
this.mappedName = resource.mappedName();
//属性注入
protected Object getResourceToInject(Object target, String requestingBeanName) {
//如果当前Bean名称不为空
if (StringUtils.hasLength(this.beanName)) {
//如果容器不为null,并且容器中存在指定名称的Bean
if (beanFactory != null && beanFactory.containsBean(this.beanName)) {
//直接从本地容器中获取指定名称的Bean
Object bean = beanFactory.getBean(this.beanName, this.lookupType);
//向容器注册Bean名称
if (beanFactory instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) beanFactory).registerDependentBean(this.beanName, requestingBeanName);
//返回从本地容器中获取到的Bean对象
//如果元素有默认名称,且元素的JNDI名称为空
else if (this.isDefaultName && !StringUtils.hasLength(this.mappedName)) {
throw new NoSuchBeanDefinitionException(this.beanName,
"Cannot resolve 'beanName' in local BeanFactory. Consider specifying a general 'name' value instead.");
//通过JNDI查找指定名称资源
return getResource(this, requestingBeanName);
从上面对@Resource、WebService和EJB相关注解解析源码的分析中,我们可以看出,Spring主要使用JDNI查找方式获取这三类注解资源,另外,由源码的“if(this.member instanceof Method&& resourceName.startsWith("set") && resourceName.length() & 3)”判断条件,我们可以看出这三类注解只能添加在字段上,或者set属性方法上,在get属性方法上添加这三类注解将是无法被解析的。
5.RequiredAnnotationBeanPostProcessor:
是Spring中用于处理@Required注解的,@Required注解强制要求Bean属性必须被配置,当Spring容器对Bean的属性进行依赖注入时,配置了@Required注解的属性,Spring容器会检查依赖关系是否设置,按照其主要功能分析其主要实现源码:
[java] view plaincopy
//注入属性
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException {
//如果容器缓存中没有指定Bean名称
if (!this.validatedBeanNames.contains(beanName)) {
//如果指定Bean定义中没有设置skipRequiredCheck属性
if (!shouldSkip(this.beanFactory, beanName)) {
List&String& invalidProperties = new ArrayList&String&();
//遍历所有属性
for (PropertyDescriptor pd : pds) {
//如果属性添加了@Required注解,且属性集合中不包含指定名称的属性
if (isRequiredProperty(pd) && !pvs.contains(pd.getName())) {
//当前属性为无效的属性
invalidProperties.add(pd.getName());
//如果无效属性集合不为空
if (!invalidProperties.isEmpty()) {
throw new BeanInitializationException(buildExceptionMessage(invalidProperties, beanName));
//将Bean名称缓存到容器中
this.validatedBeanNames.add(beanName);
//返回经过验证的属性值
//检查给定属性上是否添加了@Required注解
protected boolean isRequiredProperty(PropertyDescriptor propertyDescriptor) {
//获取给定属性的写方法(setter方法)
Method setter = propertyDescriptor.getWriteMethod();
//检查给定属性方法上是否存在指定类型的注解
return (setter != null && AnnotationUtils.getAnnotation(setter, getRequiredAnnotationType()) != null);
PersistenceAnnotationBeanPostProcessor是Spring中用于处理JPA相关注解的Bean后置处理器,主要解析和处理@PersistenceUnit、@PersistenceContext注解,其主要作用是为JPA的实体管理器工厂(EntityManagerFactory)和实体管理器(EntityManager)注入相应的持久化单元(PersistenceUnit)或持久化上下文(PersistenceContext)。按照其主要功能分析其主要实现源码:
(1).处理和查找持久化元信息:
[java] view plaincopy
//处理持久化相关属性
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
//查找给定类中持久化元信息
InjectionMetadata metadata = findPersistenceMetadata(bean.getClass());
//为Bean注入持久化属性
metadata.inject(bean, beanName, pvs);
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of persistence dependencies failed", ex);
//查找给定类中的持久化元信息
private InjectionMetadata findPersistenceMetadata(final Class clazz) {
//首先从容器缓存中查找给定类的元信息
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
//容器缓存中没有给定类的元信息
if (metadata == null) {
//线程同步,以确保容器中数据的一致性
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(clazz);
if (metadata == null) {
//创建一个存储所有注入元信息的集合
LinkedList&InjectionMetadata.InjectedElement& elements = new LinkedList&InjectionMetadata.InjectedElement&();
Class&?& targetClass =
//递归遍历给定类及其所有非Object类型的基类
//创建一个存储当前类注入信息的集合
LinkedList&InjectionMetadata.InjectedElement& currElements = new LinkedList&InjectionMetadata.InjectedElement&();
//遍历给定类的所有声明字段
for (Field field : targetClass.getDeclaredFields()) {
//获取当前字段上的@PersistenceContext注解
PersistenceContext pc = field.getAnnotation(PersistenceContext.class);
//获取当前字段上的@PersistenceUnit注解
PersistenceUnit pu = field.getAnnotation(PersistenceUnit.class);
//当前字段上配置了@PersistenceContext或者@PersistenceUnit注解
if (pc != null || pu != null) {
//持久化注解不支持在静态字段上配置
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("Persistence annotations are not supported on static fields");
//将配置了持久化注解的字段添加到当前类的注入元信息集合中
currElements.add(new PersistenceElement(field, null));
//遍历给定类的所有声明方法
for (Method method : targetClass.getDeclaredMethods()) {
//获取当前方法上的@PersistenceContext注解
PersistenceContext pc = method.getAnnotation(PersistenceContext.class);
//获取当前方法上的@PersistenceUnit注解
PersistenceUnit pu = method.getAnnotation(PersistenceUnit.class);
//当前方法上配置了@PersistenceContext或者@PersistenceUnit注解
if (pc != null || pu != null &&
//静态方法上不支持配置持久化注解
method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("Persistence annotations are not supported on static methods");
//持久化注解只能配置了只有一个参数的方法上
if (method.getParameterTypes().length != 1) {
throw new IllegalStateException("Persistence annotation requires a single-arg method: " + method);
//获取当前方法的属性描述符
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
//将配置了持久化注解的方法添加到当前类的注入元信息集合中
currElements.add(new PersistenceElement(method, pd));
//将当前类的注入元信息添加到注入元信息集合中
elements.addAll(0, currElements);
//获取当前类的基类
targetClass = targetClass.getSuperclass();
//当前类的基类不为null,且不是Object,递归注入基类元信息
while (targetClass != null && targetClass != Object.class);
metadata = new InjectionMetadata(clazz, elements);
//向容器中缓存给定类的注入元信息
this.injectionMetadataCache.put(clazz, metadata);
//返回查找到的注入元信息
(2).根据持久化单元名称获取持久化上下文、持久化单元和实体管理器工厂:
PersistenceAnnotationBeanPostProcessor最重要的核心功能就是根据持久化单元名称获取相应的持久化上下文,持久化单元或者实体管理器工厂,源码如下:
[java] view plaincopy
//根据持久化单元名称获取实体管理器工厂
protected EntityManagerFactory getPersistenceUnit(String unitName) {
//如果持久化单元不为null
if (this.persistenceUnits != null) {
//获取持久化单元名称
String unitNameForLookup = (unitName != null ? unitName : "");
//如果持久化单元名称为空
if ("".equals(unitNameForLookup)) {
//将默认的持久化单元名称作为持久化单元名称
unitNameForLookup = this.defaultPersistenceUnitN
//获取持久化单元的JNDI名称
String jndiName = this.persistenceUnits.get(unitNameForLookup);
if (jndiName == null && "".equals(unitNameForLookup) && this.persistenceUnits.size() == 1) {
//从持久化单元中获取JNDI名称
jndiName = this.persistenceUnits.values().iterator().next();
if (jndiName != null) {
//查找指定JNDI名称的实体管理器工厂
return lookup(jndiName, EntityManagerFactory.class);
catch (Exception ex) {
throw new IllegalStateException("Could not obtain EntityManagerFactory [" + jndiName + "] from JNDI", ex);
//查找给定持久化单元名称的实体管理器
protected EntityManager getPersistenceContext(String unitName, boolean extended) {
//获取持久化上下文
Map&String, String& contexts = (extended ? this.extendedPersistenceContexts : this.persistenceContexts);
//持久化上下文不为null
if (contexts != null) {
String unitNameForLookup = (unitName != null ? unitName : "");
if ("".equals(unitNameForLookup)) {
unitNameForLookup = this.defaultPersistenceUnitN
//从持久化上下文中获取给定持久化单元名称的JNDI
String jndiName = contexts.get(unitNameForLookup);
if (jndiName == null && "".equals(unitNameForLookup) && contexts.size() == 1) {
jndiName = contexts.values().iterator().next();
if (jndiName != null) {
//查找指定JNDI名称的实体管理器
return lookup(jndiName, EntityManager.class);
catch (Exception ex) {
throw new IllegalStateException("Could not obtain EntityManager [" + jndiName + "] from JNDI", ex);
//从Spring容器中查找给定名称的实体管理器工厂
protected EntityManagerFactory findEntityManagerFactory(String unitName, String requestingBeanName)
throws NoSuchBeanDefinitionException {
//当前Spring容器为null
if (this.beanFactory == null) {
throw new IllegalStateException("ListableBeanFactory required for EntityManagerFactory bean lookup");
//获取持久化单元名称
String unitNameForLookup = (unitName != null ? unitName : "");
//如果持久化单元名称为空,则将容器默认持久化单元名称作用持久化单元名称
if ("".equals(unitNameForLookup)) {
unitNameForLookup = this.defaultPersistenceUnitN
//如果持久化单元名称不为空,查找给定持久化单元名称的实体管理器工厂
if (!"".equals(unitNameForLookup)) {
return findNamedEntityManagerFactory(unitNameForLookup, requestingBeanName);
//如果持久化单元名称为空,获取容器中默认的实体管理器工厂
return findDefaultEntityManagerFactory(requestingBeanName);
//查找给定持久化单元名称的实体管理器工厂
protected EntityManagerFactory findNamedEntityManagerFactory(String unitName, String requestingBeanName)
throws NoSuchBeanDefinitionException {
//从Spring所有容器中查找给定名称的实体管理器工厂对象
EntityManagerFactory emf = EntityManagerFactoryUtils.findEntityManagerFactory(this.beanFactory, unitName);
//将持久化单元名称和查找到的实体管理器工厂对象向Spring容器注册
if (this.beanFactory instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(unitName, requestingBeanName);
//获取容器默认的实体管理器工厂
protected EntityManagerFactory findDefaultEntityManagerFactory(String requestingBeanName)
throws NoSuchBeanDefinitionException{
//从Spring所有容器中查找给定类型的Bean的名称
String[] beanNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, EntityManagerFactory.class);
//如果从Spring容器中刚好查找到一个Bean名称
if (beanNames.length == 1) {
//持久化单元名称就是查找到的Bean名称
String unitName = beanNames[0];
//从Spring容器中查找给定持久化单元名称的实体管理器工厂Bean
EntityManagerFactory emf = (EntityManagerFactory) this.beanFactory.getBean(unitName);
//将查找到的实体管理器工厂Bean和持久化单元名称向Spring容器注册
if (this.beanFactory instanceof ConfigurableBeanFactory) {
((ConfigurableBeanFactory) this.beanFactory).registerDependentBean(unitName, requestingBeanName);
throw new NoSuchBeanDefinitionException(
EntityManagerFactory.class, "expected single bean but found " + beanNames.length);
类是Spring中用于解析持久化相关注解,并提供相应的实体管理器工厂或者实体管理器,PersistenceElement解析持久化相关注解的源码如下:
[java] view plaincopy
//解析持久化注解
public PersistenceElement(Member member, PropertyDescriptor pd) {
super(member, pd);
//获取当前元素对象
AnnotatedElement ae = (AnnotatedElement)
//获取当前元素对象的@PersistenceContext注解
PersistenceContext pc = ae.getAnnotation(PersistenceContext.class);
//获取当前元素对象的@PersistenceUnit注解
PersistenceUnit pu = ae.getAnnotation(PersistenceUnit.class);
//资源类型为实体管理器
Class resourceType = EntityManager.
//如果元素配置的持久化上下文不为null
if (pc != null) {
//如果元素配置的持久化单元也不为null
if (pu != null) {
//持久化上下文和持久化单元只能二选一,不能同时配置
throw new IllegalStateException("Member may only be annotated with either " +
"@PersistenceContext or @PersistenceUnit, not both: " + member);
Properties properties =
//获取持久化上下文的属性
PersistenceProperty[] pps = pc.properties();
//如果持久化上下文属性不为空
if (!ObjectUtils.isEmpty(pps)) {
properties = new Properties();
//将持久化上下文的属性名称和属性值保存到属性集合中
for (PersistenceProperty pp : pps) {
properties.setProperty(pp.name(), pp.value());
//设置元素的持久化单元名称
this.unitName = pc.unitName();
//设置元素的持久化类型为实体管理器(EntityManager)
this.type = pc.type();
//设置元素的持久化属性
this.properties =
//如果持久化上下文为null
//持久化资源类型为实体管理器工厂
resourceType = EntityManagerFactory.
this.unitName = pu.unitName();
//检查给定的持久化资源类型是字段还是方法类型
checkResourceType(resourceType);
从上面的源码我们可以看到,当配置了持久化上下文时,容器会自动选择实体管理器作用持久化资源类型,如果配置了持久化单元时,选择实体管理器工厂作为持久化资源类型。
(4).获取并注入持久化资源:
PersistenceElement类对持久化注解解析获取到基本的持久化信息之后,就可以根据注解配置的持久化信息获取并注入相应的持久化资源,源码如下:
[java] view plaincopy
//获取并注入持久化资源
protected Object getResourceToInject(Object target, String requestingBeanName) {
//持久化资源类型不为null,创建实体管理器
if (this.type != null) {
return (this.type == PersistenceContextType.EXTENDED ?
resolveExtendedEntityManager(target, requestingBeanName) :
resolveEntityManager(requestingBeanName));
//持久化资源类型为null,创建实体管理器工厂
return resolveEntityManagerFactory(requestingBeanName);
//创建扩展的实体管理器
private EntityManager resolveExtendedEntityManager(Object target, String requestingBeanName) {
//以持久化单元名称作为JNDI名称获取持久化上下文作为实体管理器
EntityManager em = getPersistenceContext(this.unitName, true);
//如果根据JNDI获取到的持久化上下文为null
if (em == null) {
//以持久化单元名称作为JNDI名称获取实体管理器工厂
EntityManagerFactory emf = getPersistenceUnit(this.unitName);
//没有获取到指定JNDI名称的实体管理器工厂
if (emf == null) {
//根据持久化单元名称向Spring容器查找指定名称的实体管理器工厂
emf = findEntityManagerFactory(this.unitName, requestingBeanName);
//根据实体管理器工厂和持久化属性创建一个容器管理的实体管理器
em = ExtendedEntityManagerCreator.createContainerManagedEntityManager(emf, this.properties);
//创建实体管理器代理委派调用的实体管理器
if (em instanceof EntityManagerProxy &&
beanFactory != null && !beanFactory.isPrototype(requestingBeanName)) {
extendedEntityManagersToClose.put(target, ((EntityManagerProxy) em).getTargetEntityManager());
//创建实体管理器
private EntityManager resolveEntityManager(String requestingBeanName) {
//以持久化单元名称作为JNDI名称获取持久化上下文作为实体管理器
EntityManager em = getPersistenceContext(this.unitName, false);
//如果根据JNDI获取到的持久化上下文为null
if (em == null) {
//以持久化单元名称作为JNDI名称获取实体管理器工厂
EntityManagerFactory emf = getPersistenceUnit(this.unitName);
//没有获取到指定JNDI名称的实体管理器工厂
if (emf == null) {
//根据持久化单元名称向Spring容器查找指定名称的实体管理器工厂
emf = findEntityManagerFactory(this.unitName, requestingBeanName);
//创建一个共享事务管理的实体管理器代理
if (emf instanceof EntityManagerFactoryInfo &&
((EntityManagerFactoryInfo) emf).getEntityManagerInterface() != null) {
//根据JPA实现提供商类型创建相应的实体管理器
em = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties);
//根据持久化注解配置的持久化资源类型创建实体管理器
em = SharedEntityManagerCreator.createSharedEntityManager(emf, this.properties, getResourceType());
//创建实体管理器工厂
private EntityManagerFactory resolveEntityManagerFactory(String requestingBeanName) {
//以持久化单元名称作为JNDI名称获取实体管理器工厂
EntityManagerFactory emf = getPersistenceUnit(this.unitName);
//没有获取到指定JNDI名称的实体管理器工厂
if (emf == null) {
//根据持久化单元名称向Spring容器查找指定名称的实体管理器工厂
emf = findEntityManagerFactory(this.unitName, requestingBeanName);
Spring中还有其他处理注解的Bean后置处理器,其基本的实现原理与上面分析的这4个最常用的注解Bean后置处理器类似,注解其实也没什么神秘的,和XML配置文件类似都是一种配置的方式而已,只不过利用JDK的反射机制,在编译时或者运行时动态获取所配置的信息而已,注解本身只是个标识,注解的真正意义在于通过注解标识获取注解所在对象的信息以及注解中配置的信息。
Spring的注解方式只是简化了XML配置文件,可以在读入Bean定义资源时可以动态扫描给定的路径,在解析和依赖注入时,XML方式配置的Bean,Spring需要解析XML文件,注解方式配置的Bean,Spring需要通过JDK的反射机制获取注解配置的信息。
本文固定链接:
[上一篇][下一篇]
最新文章随机精彩热门排行
精彩内容获取超时,请稍候...
日志总数:3904 篇
评论总数:146 评
标签数量:4475 个
链接总数:4 条
建站日期:
运行天数:1469 天

我要回帖

更多关于 jsonproperty注解 的文章

 

随机推荐