Spring——基于注解配置bean

文章目录

一、通过注解分别创建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 属性。

上一篇:Spring Core


下一篇:【架构师面试-Java编程基本功-15】-bean的装配与自动装配