Online Shop version regeneration series: all of them are caused by automatic injection in spring configurations

Source: Internet
Author: User

When configuring bean managed by spring container, an easy-to-use function is automatic injection. Bean dependent beans can be automatically set according to different rules, I believe the most common method is to set default-autowire = "byname; in this way, we can reduce a lot of XML code during configuration. When we add or reduce bean injection in Java code, we do not need to change the xml configuration synchronously (for XML configuration method, this problem does not exist if annotation is used), which improves the coding efficiency;

Generally, this automatic injection method does not cause MS problems. However, in some special cases, it may lead to inexplicable problems, which may take a lot of time to correct errors; I encountered this problem in a recent project. The problem is probably like this: the previous applications were developed based on the Oracle single data source, and the spring configuration adopted byname automatic injection; however, due to the sharp increase in data volume, Oracle servers are overwhelmed and the resizing cost of minicomputers is too high. Therefore, we decided to transform the original application into a user-level distributed dB structure based on MySQL. In this case, you need to modify some datasource-related configurations of the DaO layer. During the adjustment process, the problem arises;

The configuration of datasource is as follows:
<Beans default-autowire = "byname"> <br/> <bean id = "datasource" class = "org. springframework. JNDI. jndiobjectfactorybean "> <br/> <property name =" cache "> <br/> <value> false </value> <br/> </property> <br/> <property name = "proxyinterface"> <br/> <value> javax. SQL. datasource </value> <br/> </property> <br/> <property name = "jndiname"> <br/> <value> JAVA: oracleds </value> <br/> </property> <br/> </bean> </P> <p> <bean id = "sqlmapclient" class = "org. springframework. orm. ibatis. sqlmapclientfactorybean "> <br/> <property name =" configlocation "> <br/> <value>/bean/ibatis/sqlmap-config.xml </value> <br/> </property> <br/> </bean> </P> <p> <bean id = "daodefinition" abstract = "true"> <br/> <property name = "sqlmapclient" ref = "sqlmapclient"/> <br/> <property name = "datasource" ref = "datasource"/> <br/> </bean> <br/> </beans>
Set parent = "daodefinition" in all DaO configurations, and extends sqlmapclientdaosupport in Java implementation;

During application transformation, we use spring-based javasactroutingdatasource to load dynamic data sources. However, because only some table data in the application can be split into databases, therefore, there will be two types of data sources in the transformed system. One is still the original Oracle master database, accessed through JNDI, the other is the newly added MySQL sub-database, and accessed through dynamic Ds;

Because abstractroutingdatasource obtains bound user information from the current thread, in the same user operation, there may be access to both the original Oracle master database and MySQL sub-database, therefore, dynamic DS must be compatible with this situation. After each db operation is completed, the variables bound to the current thread need to be cleared. This is mainly to prevent all DaO layers from being changed, but where can I automatically clear the variables bound to the current thread? Of course, in sqlmapclienttemplate, because all DaO operations are accessed through the interface encapsulated by this template, You need to inherit the class and extend all methods. The new configuration is as follows:
<Beans default-autowire = "byname"> <br/> <bean id = "mixedddbdatasource" class = "com. alisoft. eshop. DDB. datasource. mixedddbdatasource "> <br/> <property name =" ddbmetaservice "ref =" ddbmetaservice "/> <br/> <! -- The JNDI name and default value of the Oracle Data source are Java: JDBC/DS --> <br/> <! -- <Property name = "oraclejndidsname" value = "Java: oracleds "/> --> <br/> </bean> </P> <p> <bean id =" ddbsqlmapclienttemplate "class =" com. alisoft. eshop. DDB. dao. support. ddbsqlmapclienttemplate "> <br/> <property name =" sqlmapclient "ref =" sqlmapclient "/> <br/> <property name =" datasource "ref =" mixedddbdatasource "/> <br/> </bean> </P> <p> <bean id = "ddbdaodefinition" abstract = "true"> <br/> <property name = "sqlmapclienttemplate" ref = "ddbsqlmapclienttemplate"/> <br/> <property name = "ddbmetaservice" ref = "ddbmetaservice"/> <br/> </bean> <br/> </beans>
When Dao accesses MySQL database shards, parent = "ddbdaodefinition" is set and extends ddbsqlmapclientdaosupport is implemented in Java;

There is no problem with this configuration Ms. The dynamic DS has been explicitly set in the template, and the DAO implementation class has also explicitly inherited the new template class! Later, the tracking code found that:Or is it caused by automatic spring injection?!
The reason is as follows:

Sqlmapclientdaosupport can automatically inject three beans: datasource, sqlmapclient, and sqlmapclienttemplate. The injection of these three beans is sequential. In fact, datasource and sqlmapclient are all set to sqlmapclienttemplate! The problem occurs here;
In our configuration, the parent shows that the sqlmapclienttemplate is set, but the other two attributes are not set. According to the default rules of Spring Automatic injection, the bean injection of the set will first be displayed, at this time, sqlmapclienttemplate is the bean with the correct dynamic Ds. However, after the set injection is completed, spring will automatically inject and scan the Set Method in the bean based on whether or not, after Non-display bean injection is completed, the problem occurs. Spring finds the original JNDI-based bean for Injection Based on the default datasource name, And the datasource in sqlmapclienttemplate is overwritten, that is, the original correct dynamic DS is replaced with the datasource of the original Oracle master database based on JNDI!

After finding the cause, the problem is solved. There are many methods, such:

  1. Add display settings in ddbdaodefinition configuration <property name = "datasource" ref = "mixedddbdatasource"/>;
    NOTE: For the sake of insurance, the set of datasource is put after sqlmapclienttemplate, because spring will inject according to the set sequence. If it is placed before sqlmapclienttemplate, it will be overwritten by the latter, depends on the implementation of the Set Method in the injected bean;
  2. Remove the automatic injection in the DaO configuration file. In fact, the DaO layer generally does not depend on other beans and is dependent on them. Therefore, this automatic injection is completely unnecessary and brings hidden risks to the application;

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.