文章目录
- 一、通过注解分别创建Dao,Service,Controller
- 二、扫描组件
- 三、使用@autowired注解实现根据类型自动装配
- 四、资源类型的bean不止一个,autowired如何装配
- 五、@Autowired、@Resource和@Inject的区别
一、通过注解分别创建Dao,Service,Controller
1.为什么使用注解?
如果按照之前xml的方法进行配置,存在多个bean都需要一一配置,当这些bean特别多且繁杂的时候,一个一个的配置不符合人类的天性(懒),那么注解就油然而生。当我们创建bean类时,只需要优雅的在类名上面加上一行轻飘飘的注解,一个bean就被我们装到了bean的空间中。
2.表示组件(bean)的四大注解
- Controller:表述层控制器组件,标识一个受 Spring IOC 容器管理的控制层控制器组件(可以理解为一个servlet)
- Service :业务逻辑层组件,标识一个受 Spring IOC 容器管理的业务逻辑层组件(可以理解为一个service)
- Repository:持久化层组件,标识一个受 Spring IOC 容器管理的持久化层组件(可以理解为Dao)
- Component :普通组件,标识一个受 Spring IOC(啥都可以表示)
组件命名规则
① 默认情况:使用组件的简单类名首字母小写后得到的字符串作为 bean 的 id
②使用组件注解的 value 属性指定 bean 的 id 注意:事实上 Spring 并没有能力识别一个组件到底是不是它所标记的类型,即使将 @Respository 注解用在一个表述层控制器组件上面也不会产生任何错误。由此见得,这些组件其实没有多大的区别,只是为了程序猿进行逻辑上的区分。
二、扫描组件
这些组件加了注解后,如果不进行扫描的话,也无法进入bean的管理空间,在扫描组件之前,需要引入配置
xmlns:context="http://www.springframework.org/schema/context"
在xml中添加扫描的根目录
<context:component-scan base-package="com.shang.component"/>
这样就将这些组件加入进来了。
1.<context:include-filter>子节点表示要包含的目标类
注意:通常需要与 use-default-filters 属性配合使用才能够达到“仅包含某些 组件”这样的效果。即:通过将 use-default-filters 属性设置为 false, 禁用默认过滤器,然后扫描的就只是 include-filter 中的规则指定的 组件了。
2.<context:exclude-filter> 节点表示要排除在外的目标类 3.component-scan 下可以拥有若干个 include-filter 和 exclude-filter结点
类别 | 示例 | 说明 |
---|---|---|
annotation | com.shang.XxxAnnotation | 过滤所有标注了 XxxAnnotation 的类。这个规则根 据目标组件是否标注了指定类型的注解进行过滤。 |
assignable | com.shang.BaseXxx | 过滤所有 BaseXxx 类的子类。这个规则根据目标组 件是否是指定类型的子类的方式进行过滤。 |
aspectj | com.shang.*Service+ | 所有类名是以 Service 结束的,或这样的类的子类。 这个规则根据 AspectJ 表达式进行过滤。 |
regex | com.shang.anno.* | 所有 com.atguigu.anno 包下的类。这个规则根据正 则表达式匹配到的类名进行过滤。 |
custom | com.shang.XxxTypeFilter | 使用 XxxTypeFilter 类通过编码的方式自定义过滤 规 则 。该 类 必 须 实 现 org.springframework.core.type.filter.TypeFilter 接口 |
三、使用@autowired注解实现根据类型自动装配
首先先创建三个MVC模式的类:
@Controller
public class BookServlet {
@Autowired
private BookService bookService;
public void save() {
bookService.save();
}
}
@Service
public class BookService {
@Autowired
private BookDao bookDao;
public void save() {
System.out.println("正在调用bookDao.sava()");
bookDao.sava();
}
}
@Repository
public class BookDao {
public void sava() {
System.out.println("BookDao正在保存书--");
}
}
在xml中进行这样的配置
<?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: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/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="com.shang"></context:component-scan>
</beans>
调用方法
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans04.xml");
@Test
public void test01() {
BookServlet bookServlet = applicationContext.getBean(BookServlet.class);
bookServlet.save();
}
神奇的事情发生了,
正在调用bookDao.sava()
BookDao正在保存书--
成员类型被注入进来,而且没有使用set方法,这是一个很神奇的点,经过查阅资料发现。
在java的反射机制中,存在着这样一个方法setAccessible(boolean)方法,如果将其设置为true,我们就可以直接访问私有的成员,可以直接对这些值进行更改。
那么加了@Autowired注解后,Spring就自动将这个这个成员的访问控制检查关闭了,所有就不需要set()
四、资源类型的bean不止一个,autowired如何装配
@Autowired原理:
- 先根据类型去容器中找到对应的组件
- 找到一个,找到就赋值
- 没有找到,抛异常
- 找到多个,根据变量名作为id继续匹配
例子:
@Service
public class BookService {
@Autowired
private BookDao bookDao;
public void save() {
System.out.println("BookService");
bookDao.sava();
}
}
@Service
public class BookServiceExt extend BookService{
@Autowired
private BookDao bookDao;
@Override
public void save() {
System.out.println("BookServiceExt---");
}
}
1.第一次调用:注入BookService
@Autowired
private BookService bookService;
输出
BookService
BookDao正在保存书--
2.第二次调用,注入BookServiceExt
@Autowired
private BookServiceExt bookServiceExt;
输出
BookServiceExt---
BookDao正在保存书--
3.第三次调用,注入BookService,但是只将BookServiceExt放入容器
输出
BookServiceExt---
BookDao正在保存书--
4.@Qualifier自定义注入
此时可以在@Qualifier 注解里提供 bean 的名称。Spring 甚至允许在方法的形参上标注@Qualifiter 注解以指定注入 bean 的名称。
@Autowired
public void hahaha(@Qualifier("bookServiceExt")BookService bookservice) {
System.out.println(bookservice);
}
五、@Autowired、@Resource和@Inject的区别
-
@Autowired注解: 最强大
-
@Resource: 注解 j2ee;java标准,扩展性更强。 要求提供一个 bean 名称的属性,若该属性为空,则自动采用标注处的 变量或方法名作为 bean 的名称。
-
@Inject: @Inject 和@Autowired 注解一样也是按类型注入匹配的 bean,但没有 reqired 属性。