前面几篇文章介绍了基于配置文件的bean的配置,Spring还提供基于注解形式来配置bean。
Spring提供了组件扫描(component scanning),能够从classpath下自动扫描侦测和具有特定注解的组件。
特定组件包括:
@Controller
@Service
@Repository
@Component
对于扫描到的组件,Spring有默认的命名策略:使用非限定类名,第一个字母小写,也可以在注解中通过value属性值标识组件的名称。
什么意思呢,不如先看一个例子:
1.创建接口UserDao
定义两个方法
package com.jd.annotation.dao;
public interface UserDao {
public void add(int a, int b);
}
2.创建UserDao的实现UserDaoImpl
实现接口方法,打印传递的数据之和和之差。
在UserDaoImpl上面标记为@Repository,通过value属性值设置为userDao
package com.jd.annotation.dao;
import org.springframework.stereotype.Repository;
@Repository("userDao")
public class UserDaoImpl implements UserDao{
public void add(int a, int b) {
int result = a+b;
System.out.println("调用加法操作,result:"+result);
}
}
3.创建userService接口
package com.jd.annotation.service;
public interface UserService {
public void addInt(int a,int b);
}
4.创建UserService接口的实现类UserServiceImpl
service层使用@Service标记,并设置value值为userService,在该类中引用UserDao接口,名字命名为userDao与UserDaoImpl的注解中设置的值对应。
@Autowired为提供的自动注入的注解,如果单纯的引用useDao为null,使用该注解后会为userDao实例化。也可以使用@Resource进行配置(@Resource是javax包下提供的注解方式,@Autowired是Spring提供的注解方式)。
像这种通过@Autowired方式注入,如果在IOC容器中找不到该实例,那么Spring启动时就会报错。比如这里的UserDaoImpl并没有通过注解或者配置文件加入到SpringIoC容器,那么在启动的时候就会报错。这个时候怎么解决呢?
可以在@Autowired中配置是否需要:@Autowired(required=false)忽略该bean的存在。
那么问题又来了,如果我的一个接口有多个实现类怎么办呢,我的@Autowired该装配那个实现类呢?
1.通过上面介绍的在注解的后面添加value值指定到底是那个bean,如@Repository(“userDao”),那么就会按照userDao寻找
2.通过在引用上面添加
@Qualifier("userDao")
private UserDao userDao;
package com.jd.annotation.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.jd.annotation.dao.UserDao;
@Service("userService")
public class UserServiceImpl implements UserService{
@Autowired
//@Autowired(required=false)
private UserDao userDao;
public void addInt(int a ,int b) {
userDao.add(a, b);
}
}
5.配置包扫描
创建配置文件springannotation.xml
上面提到spring就是通过一个扫描组件,对指定的注解扫描加载注册的。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!--
base-package:扫描 com.jd.annotation包及其下面的子包,
resource-pattern:指定只扫描哪个子包。如:dao/*.class
-->
<context:component-scan base-package="com.jd.annotation"/>
</beans>
与之前的配置文件方式不同,这里只使用了以行的配置,配置包扫描。
6.测试:
package com.jd.annotation;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jd.annotation.service.UserService;
public class AnnotationTest {
private ApplicationContext ac = null;
private UserService userService = null;
{
ac = new ClassPathXmlApplicationContext("springannotation.xml");
userService = ac.getBean(UserService.class);
}
@Test
public void testAnnotation(){
userService.addInt(1, 2);
}
}
结果:
调用加法操作,result:3
虽然我们并没有在配置文件中将所有的bean都进行配置,但是很显然在我们调用该bean的时候,该bean已经被加载到spring的IOC容器之中。
这其中有一些细节问题:
比如扫描的配置:
<context:component-scan base-package="com.jd.annotation">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
或者是
<!--如果需要扫描指定的某个包,需要修改use-default-filters=false,不然会扫描所有base-package包下的内容-->
<context:component-scan base-package="com.jd.annotation" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
提供了<context:include-filter >
和<context:exclude-filter>
<context:include-filter >
指定需要扫描的注解
<context:exclude-filter>
指定不需要扫描的注解
比如在配置springmvc的时候,由于springmvc只负责前后台的交互,所以在配置springmvc配置文件的时候就可以指定只扫描@Controller注解,而在spring的applicationContext配置文件中可以忽略前端的@Controller注解。
也可以通过type=”assignable”配置只扫描某个类或者不扫描某个类。
<context:component-scan base-package="com.jd.annotation">
<context:exclude-filter type="assignable" expression="com.jd.annotation.dao.UserDaoImpl"/>
</context:component-scan>