Inside-springframework-bean-definition

本文详细解析了Spring框架中BeanDefinition的生成流程,从ApplicationContext的refresh方法开始,逐步深入到BeanDefinition的创建与注册过程。重点介绍了XmlWebApplicationContext、XmlBeanDefinitionReader等组件的作用及其实现细节。
 

Inside-springframework-bean-definition

 

说明:BeanDefinition的生成原理和过程,阅读源程序的一些笔记,已备以后回顾。

过程:1)遍历所有的Spring配置文件(ApplicationContext*.xmlm)。

      2)将每个bean节点的内容包装为一个BeanDefinition对象。

      3)将包装好的BeanDefinition对象和beanName存入beanFactory中。

☆ 起势

public abstract class AbstractApplicationContext extends DefaultResourceLoader

        implements ConfigurableApplicationContext, DisposableBean {

 

        public void refresh() throws BeansException, IllegalStateException {

        synchronized (this.startupShutdownMonitor) {

            refreshBeanFactory(); (1)

    }

}

 

      public abstract class AbstractRefreshableApplicationContext

extends AbstractApplicationContext {

    protected final void refreshBeanFactory() throws BeansException {

        //源起

        DefaultListableBeanFactory beanFactory = createBeanFactory(); (2)

        //模版模式,调用子类XmlWebApplicationContext同名方法

        loadBeanDefinitions(beanFactory); (3)

}

 

protected DefaultListableBeanFactory createBeanFactory() {

    return new DefaultListableBeanFactory(getInternalParentBeanFactory());(2)

}

}

 

public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)

throws IOException {(3)

        XmlBeanDefinitionReader beanDefinitionReader = new

XmlBeanDefinitionReader(beanFactory); (4)

 

        loadBeanDefinitions(beanDefinitionReader);)(5)

    }

 

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) (5)

throws BeansException, IOException {

        String[] configLocations = getConfigLocations();

        if (configLocations != null) {

            for (int i = 0; i < configLocations.length; i++) {

                /**

/*configLocations[i]=

/WEB-INF/applicationContext-dudu.xml

**/

                reader.loadBeanDefinitions(configLocations[i]);(6)

            }

        }

    }

}

 

(6注:委派)

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {

    public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {

        int loadCount = loadBeanDefinitions(resources);(7)

    }

}

 

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {(8)

    public int loadBeanDefinitions(EncodedResource encodedResource) throws

BeanDefinitionStoreException {

        InputStream inputStream = encodedResource.getResource().getInputStream(); (9)

   

        return doLoadBeanDefinitions(inputSource, encodedResource.getResource());(10)

    }

 

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)(10)

            throws BeanDefinitionStoreException {

            //读取xml配置文件中的内容

            Document doc = this.documentLoader.loadDocument(

                    inputSource, this.entityResolver, this.errorHandler, validationMode,

this.namespaceAware);

            return registerBeanDefinitions(doc, resource);(11)

    }

 

    (11)

public int registerBeanDefinitions(Document doc, Resource resource) throws

BeanDefinitionStoreException {

//实际的类是DefaultBeanDefinitionDocumentReader

        BeanDefinitionDocumentReader documentReader =

createBeanDefinitionDocumentReader();

 

        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));(12)

    }

}

 

public class ServletContextResource extends AbstractResource {

        public InputStream getInputStream() throws IOException {

        InputStream is = this.servletContext.getResourceAsStream(this.path); (9)

        return is;

    }

}

 

 

 

      public class DefaultBeanDefinitionDocumentReader

implements BeanDefinitionDocumentReader {

12注)

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {

 

        /**

        *生成委派对象delegate,并生成默认bean对象DocumentDefaultsDefinition

        *存入其中

        **/

        BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);(13)

 

        parseBeanDefinitions(root, delegate);(14)

    }

 

    (13)

    protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext,

Element root) {

        delegate.initDefaults(root); 14

    }

 

    //中间不重要处跳过

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {

    parseDefaultElement(ele, delegate); (15)

}

 

15注)

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {

    processBeanDefinition(ele, delegate); (16)

}

 

16注)

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

    //这是最后生成的beanDefinition的包装对象,具体生成过程在步骤18

    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 17

 

    //将生成beanDefinitionNamebeanDefinition放入beanFactory

    // getReaderContext().getRegistry()得到的是beanFactory对象

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,

getReaderContext().getRegistry());(16)

}

}

 

      public class BeanDefinitionParserDelegate {

(14注:beanDefinition初时值对象)

    public void initDefaults(Element root) {

        DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();

        defaults.setLazyInit(root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE));

        defaults.setAutowire(root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE));

        defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATT

RIBUTE));

        if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {

            defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));

        }

        if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {

            defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));

        }

        defaults.setMerge(root.getAttribute(DEFAULT_MERGE_ATTRIBUTE));

        defaults.setSource(this.readerContext.extractSource(root));

 

        this.defaults = defaults;

        this.readerContext.fireDefaultsRegistered(defaults);

    }

 

    17注)

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition

containingBean) {

//example:id = dataSource

        String id = ele.getAttribute(ID_ATTRIBUTE);

   

        //经过这一步后beanDefinition对象生成赋值完毕(19

AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName,

containingBean); (18)

 

        //返回beanDefinition对象的包装类

        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);

    }

 

    19注)

    public AbstractBeanDefinition parseBeanDefinitionElement(

            Element ele, String beanName, BeanDefinition containingBean) {

//example: className= //org.apache.commons.dbcp.BasicDataSource

        className = ele.getAttribute(CLASS_ATTRIBUTE);

        this.parseState.push(new BeanEntry(beanName));

       

        AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(

                    parent, className, this.readerContext.

getReader().getBeanClassLoader()); (20)

 

        //以下步骤为BeanDefinition对象赋值

        bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));

        //如果条件不符合,就将DocumentDefaultsDefinition

//对象的属性赋值给BeanDefinition对象

        lazyInit = this.defaults.getLazyInit();

        bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

        bd.setAutowireMode(getAutowireMode(autowire));

        bd.setDependencyCheck(getDependencyCheck(dependencyCheck));

        … …

        //bean的属性值赋给BeanDefinitioin对象

        parsePropertyElements(ele, bd); (21)

 

        return bd;

    }

public void parsePropertyElement(Element ele, BeanDefinition bd) { (21)

    //sample: propertyName =driverClassName

    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);

    this.parseState.push(new PropertyEntry(propertyName));

    //sample: val = com.mysql.jdbc.Driver,取出bean属性中的value并包装为对象   

    Object val = parsePropertyValue(ele, bd, propertyName); (22)

    PropertyValue pv = new PropertyValue(propertyName, val);

    //将生成propertyValue对象赋值给BeanDefinition

    bd.getPropertyValues().addPropertyValue(pv);

}

}

 

      public class BeanDefinitionReaderUtils {

20注)

        public static AbstractBeanDefinition createBeanDefinition(

            String parent, String className, ClassLoader classLoader) throws

ClassNotFoundException {

            bd = new RootBeanDefinition();

            bd.setBeanClassName(className);

 

            return bd;

    }

        (16)

        public static void registerBeanDefinition(

            BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory)

throws BeansException {

 

            23

            beanFactory.registerBeanDefinition(beanName, bdHolder.getBeanDefinition());

        }

}

 

(23)

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory

implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {

    //将生成beanDefinitionNamebeanDefinition放入beanFactory

    this.beanDefinitionNames.add(beanName);

    this.beanDefinitionMap.put(beanName, beanDefinition);

}

}

 

 

 

### Java JPA 插入对象时遇到 InvalidDataAccessApiUsageException 和 TransactionRequiredException 的原因与解决方案 在使用 Java JPA 进行对象插入的过程中,如果遇到了 `org.springframework.dao.InvalidDataAccessApiUsageException` 或者 `javax.persistence.TransactionRequiredException` 错误,通常是因为以下几种情况之一引起的。以下是针对这些问题的详细分析和解决方法。 --- #### 1. **InvalidDataAccessApiUsageException 原因及解决办法** 此异常通常是由于尝试执行更新或删除查询(update/delete query),而这些操作需要显式的事务支持[^1]。然而,在某些情况下,开发者可能错误地将 DML 操作当作普通的 SELECT 查询来处理,这就会引发此类问题。 ##### 解决方案 确保所有的修改型操作都处于一个有效的事务之中。可以通过 Spring Framework 提供的 `@Transactional` 注解来自动管理事务生命周期。 ```java @Service public class UserService { @Autowired private UserRepository userRepository; @Transactional public void saveUser(User user) { userRepository.save(user); // Save operation inside transactional context. } } ``` 另外需要注意的是,如果你正在调用自定义 JPQL 更新/删除语句而不是简单的保存实体实例的方法,则同样也需要在一个活动的事物当中运行它们: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { @Modifying @Query("UPDATE User u SET u.name = ?1 WHERE u.id = ?2") @Transactional int updateNameById(String name, long id); } ``` 以上例子展示了如何利用 `@Modifying`, `@Query` 及再次强调了 `@Transactional` 对于变更数据库状态的操作的重要性. --- #### 2. **TransactionRequiredException 原因及解决办法** 这个例外表明当前线程里不存在活跃的事务或者所使用的 EntityManager 不属于任何事务。即使已经标注了服务层函数为 `@Transactional` ,仍然可能出现这个问题,主要原因可能是: - 配置文件缺失必要的声明式事务管理器 bean 定义。 - AOP代理机制失效(比如直接内部调用而非通过接口)。 - 使用原生 Hibernate API 而非基于Spring Data JPA的方式访问数据源。 ##### 解决方案 确认项目已正确定义了一个 PlatformTransactionManager Bean 并且它被正确注入到了相应的组件中去。例如下面这段XML配置片段用于传统Spring XML风格的应用程序上下文中启用声明性的事务控制: ```xml <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- Enable annotation-driven transactions --> <tx:annotation-driven/> ``` 如果是采用Java Config形式的话则应该像这样子做: ```java @Configuration @EnableTransactionManagement public class AppConfig { @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { ... } @Bean public PlatformTransactionManager transactionManager(EntityManagerFactory emf){ return new JpaTransactionManager(emf); } } ``` 此外还要注意避免自我调用导致AOP拦截失败的情形发生;即不要让同一类内的另一个带有@Transactional标记的方法互相呼叫彼此——因为那样就不会触发环绕通知进而建立新的事物环境了。 最后一点就是假如你是混合编程模型的话记得切换回纯JPA/Spring Data JPA路径上来完成CRUD动作,减少不必要的复杂度引入。 --- #### 3. **代码示例** 这里给出一个完整的例子展示怎样安全可靠地向数据库新增一条记录的同时规避上述提到的各种潜在陷阱。 ```java // Entity Class Definition @Entity @Table(name = "users") public class User implements Serializable{ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; private String username; private String passwordHash; // Standard constructors/getters/setters omitted for brevity... } // Repository Interface Declaration public interface UserRepository extends CrudRepository<User,Long>{} // Service Layer Implementation With Proper Exception Handling And Transactions Management @Service public class UserServiceImpl implements UserService{ @Autowired private UserRepository repo; /** * Persists given entity into database within properly managed transaction scope. */ @Override @Transactional(propagation = Propagation.REQUIRED, rollbackFor={RuntimeException.class}) public boolean registerNewAccount(@Validated final Account accountDetails)throws ServiceException{ try{ User newUser=new User(); BCryptPasswordEncoder encoder=new BCryptPasswordEncoder(); newUser.setUsername(accountDetails.getUsername()); newUser.setPasswordHash(encoder.encode(accountDetails.getPassword())); this.repo.save(newUser); log.info("Successfully registered new account."); return true; }catch(DataIntegrityViolationException ex){ throw new ServiceException("Username already exists.",ex); } catch(Exception unexpectedError){ log.error("Unexpected error occurred during registration process",unexpectedError); throw new ServiceException("Internal server error.Please retry later.",unexpectedError); } } } ``` --- ### 总结 综上所述,为了防止出现 `org.springframework.dao.InvalidDataAccessApiUsageException` 和 `javax.persistence.TransactionRequiredException` 类似的错误消息,应当始终保证每一个影响到持久化单元的动作都是发生在受控的事务之下,并且合理运用框架所提供的特性如 `@Transactional` 来简化开发流程。同时也要留意项目的整体架构设计是否符合最佳实践原则,这样才能构建起健壮稳定的企业级应用系统。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值