XML and Annotation Combined Method
Important notes:
- In actual enterprise development, pure XML mode is rarely used anymore
- Introducing annotation functionality does not require introducing additional JARs
- In XML + annotation combined mode, the XML file still exists, so the Spring IoC container still starts by loading XML
- Which Bean definitions need to be written in XML and which use annotations
Simply put: Bean definitions for third-party JARs are in XML, while Beans you develop yourself use annotation method.
XML Tags and Annotation Correspondence
| XML Tag | Annotation |
|---|---|
<bean> | @Component, @Repository, @Service, @Controller |
<property> | @Value |
<constructor-arg> | Constructor injection |
DI Dependency Injection Annotation Implementation
It is recommended to use @Autowired, which is an annotation provided by Spring, using a byType injection strategy:
public class WzkTransferServiceImpl {
@Autowired
private WzkAccountDao wzkAccountDao;
}
As shown in the code above, this assembly will go to the Spring container to find the class of type AccountDao and inject it. This creates a problem: when one type has multiple Bean values, it becomes impossible to choose which one to inject. At this point, we need to use the @Qualifier annotation together.
@Qualifier tells Spring which object to inject:
public class WzkTransferServiceImpl {
@Autowired
@Qualifier(name="jdbcWzkAccountDaoImpl")
private WzkAccountDao wzkAccountDao;
}
Of course, we can also use the @Resource annotation provided by JDK, which defaults to byName auto-injection:
public class WzkTransferService {
@Resource
private AccountDao accountDao;
@Resource(name="studentDao")
private StudentDao studentDao;
@Resource(type="TeacherDao")
private TeacherDao teacherDao;
@Resource(name="manDao",type="ManDao")
private ManDao manDao;
}
Important notes:
- If both name and type are specified, search for the unique matching Bean in the Spring context for assembly
- If name is specified, search in the context for the Bean matching the name (id) for assembly; throw exception if not found
- If type is specified, search in the context for the unique Bean matching the type for assembly; throw exception if not found or multiple found
- If neither name nor type is specified, automatic byName assembly is used
Important: Resource has been removed in JDK 11. If you need to use it, you need to introduce the JAR separately:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
applicationContext.xml Configuration
Content as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
">
</beans>
web.xml Configuration
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
Configuration Transformation
Next, we transform the pure XML mode code to annotation + XML mode, freeing up some XML.
For example, in pure XML mode, we wrote:
<!-- Configure Bean -->
<bean id="wzkTransferService" class="wzk.service.impl.WzkTransferServiceImpl">
<constructor-arg name="wzkAccountDao" ref="wzkAccountDao"></constructor-arg>
</bean>
The purpose is to let Spring take over our Bean. At this point, we can remove all these Bean configurations and use annotations to satisfy our Bean management.
At this point, we remove the Bean XML configuration and add annotations to the Beans that need to be managed by Spring, along with DI management. But at this time, Spring doesn’t know which objects to process, so we need to tell Spring which packages to scan:
<context:annotation-config/>
<context:component-scan base-package="wzk"/>
Code Transformation Example
JdbcWzkAccountDaoImpl
Here we add annotation and ID management, partially as follows:
@Component
public class JdbcWzkAccountDaoImpl implements WzkAccountDao {
@Autowired
private WzkConnectionUtils wzkConnectionUtils;
}
WzkTransferServiceImpl
@Component
public class WzkTransferServiceImpl implements WzkTransferService {
@Autowired
private WzkAccountDao wzkAccountDao;
}
WzkServlet (Important!!)
Here it should be noted that technically, we should also write @Component and @Autowired on WzkServlet to inject our WzkTransferService, but in reality, @Component and @Servlet annotations conflict.
@WebServletis a Servlet annotation, managed by Tomcat@Componentis a Spring annotation, managed by Spring
At this point, we are required not to use the Component annotation here. We need to use WebApplicationContext to handle this:
@WebServlet(name="wzkServlet", urlPatterns = "/wzkServlet")
public class WzkServlet extends HttpServlet {
private WzkTransferService wzkTransferService;
@Override
public void init() throws ServletException {
ApplicationContext context = WebApplicationContextUtils
.getWebApplicationContext(getServletContext());
this.wzkTransferService = context.getBean(WzkTransferService.class);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try {
wzkTransferService.transfer("1", "2", 100);
} catch (Exception e) {
e.printStackTrace();
System.out.println("=== transfer error ====");
}
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().print("=== WzkServlet doGet ===");
}
}
Utility Class
For some utilities we use that have dependency relationships, we also let Spring manage them:
@Component
public class WzkConnectionUtils {
private final ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
}
Summary
Through the XML and annotation combined method, we can:
- Reduce XML configuration: Let custom Beans be managed by annotations
- Retain XML configuration: For managing third-party Beans
- Component scanning: Use
<context:component-scan>to specify packages to scan - Servlet special handling: Because
@Componentconflicts with@WebServlet, need to useWebApplicationContextUtilsto manually get Beans