• Spring框架总结(四)——注解


    前面几节,通过配置xml文件,可以实现Spring 控制反转的依赖注入。不过,如果一个类中,存在很多属性、依赖不止一个目标,此时这种基于xml配置的方式就显得非常繁琐。幸好,Spirng提供了几种技巧,可以帮助我们减少xml的配置数量

    • 自动装配(autowiring)有助于减少甚至消除配置<property>元素和<constructor-arg>元素,让spring自动识别如何装配Bean的依赖关系
    • 自动检测(autodiscovery)比自动装配更进了一步,让Spring能够自动识别哪些类需要被配置成Spring Bean,从而减少对<bean>元素的使用

    一、自动装配Bean属性

    1、四中类型的自动装配

    • byName——把与Bean的属性具有相同名字(或者ID)的其他Bean自动装配到Bean的对应属性中。如果没有跟属性的名字相匹配的Bean,则该属性不进行装配。
    • byType——把与Bean的属性具有相同类型的其他Bean自动装配到Bean自动装配到Bean的对应属性中。如果没有跟属性的类型相匹配的Bean,则该属性不被装配。
    • constructor——把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造器的对应入参中。
    • autodetect——首先尝试使用constructor进行自动装配。如果失败,再尝试使用byType进行自动装配。

    这里,我们只演示第一个byName:

    第一步:创建持久层UserDao

    1 package com.justnow.dao;
    2 
    3 import com.justnow.domain.User;
    4 
    5 public class UserDao {
    6     public void findAll(User user){
    7         System.out.println(user);
    8     }
    9 }

    第二步:创建业务层的实现类UserServiceImpl,通过  set方法实现依赖注入。

     1 package com.justnow.service.impl;
     2 
     3 import com.justnow.dao.UserDao;
     4 import com.justnow.domain.User;
     5 import com.justnow.service.IUserService;
     6 
     7 public class UserServiceImpl implements IUserService {
     8     private UserDao userDao;
     9     private String otherProperty;
    10 
    11     //必须有属性的set方法,否则不能实现依赖注入
    12     public void setUserDao(UserDao userDao) {
    13         this.userDao = userDao;
    14     }
    15 
    16     public void setOtherProperty(String otherProperty) {
    17         this.otherProperty = otherProperty;
    18     }
    19 
    20     public void findAll(User user) {
    21         userDao.findAll(user);
    22         System.out.println(otherProperty);
    23     }
    24 }

    第三步:编写Spring框架的配置文件

    在bean标签中设置autowire的属性为byName:如果在该配置文件中出现一个Bean的id是userDao(userDao为userServiceImpl的属性名字),就可以实现自动装配

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4        xsi:schemaLocation="http://www.springframework.org/schema/beans
     5                            http://www.springframework.org/schema/beans/spring-beans.xsd">
     6         <bean id="userService" class="com.justnow.service.impl.UserServiceImpl" autowire="byName">
     7             <property name="otherProperty" value="利用property标签注入的值"/>
     8         </bean>
     9 
    10         <bean id="userDao" class="com.justnow.dao.UserDao"/>
    11 </beans>

    第四步:测试

     1     @Test
     2     public void test(){
     3         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     4         IUserService userService = (IUserService) context.getBean("userService");
     5         User user = new User();
     6         user.setId(1);
     7         user.setName("justnow");
     8         user.setMoney(1.0f);
     9         userService.findAll(user);
    10     }

    结果:

    修改userDao这个bean的id值为userDao2,如下:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4        xsi:schemaLocation="http://www.springframework.org/schema/beans
     5                            http://www.springframework.org/schema/beans/spring-beans.xsd">
     6         <bean id="userService" class="com.justnow.service.impl.UserServiceImpl" autowire="byName">
     7             <property name="otherProperty" value="利用property标签注入的值"/>
     8         </bean>
     9 
    10 <!--
    11         <bean id="userDao" class="com.justnow.dao.UserDao"/>
    12 -->
    13         <bean id="userDao2" class="com.justnow.dao.UserDao"/>
    14 </beans>

    看一下测试结果:

     在以后的开发中,基本上不怎么用这四种方式实现自动装配,而使用注解装配!所以,后面三个就不再演示了。

    https://github.com/justn0w/javawebdemo/tree/master/spring/Spring_Demo3

    c6e5dccfcacb13c42db41a2ed7b1145ddef700b7

    2、使用注解实现自动装配

    使用注解自动装配 Bean的属性,可以不再编写繁琐的xml文件,从而将注意力转向项目的业务逻辑。在将来的开发中,注解发挥着中流砥柱的作用!

    Spring容器默认禁用注解装配。所以,在使用基于注解的自动装配前,我们需要在Spring配置文件中启用它。最简单的启用方式是使用Spring的context命名空间配置中的<context:annotation-config>元素,如下所示:

    <?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.xsd">
    <context:annotation-config />

    红底白字是新加入的命名规则。

    (1)使用@Autowired

    场景一:在set方法上使用

    第一步:修改UserServiceImpl实现类,在setUserDao这个方法上添加注解

     1 public class UserServiceImpl implements IUserService {
     2     private UserDao userDao;
     3     private String otherProperty;
     4     //必须有属性的set方法,否则不能实现依赖注入
     5     @Autowired
     6     public void setUserDao(UserDao userDao) {
     7         this.userDao = userDao;
     8     }
     9     public void setOtherProperty(String otherProperty) {
    10         this.otherProperty = otherProperty;
    11     }
    12 
    13     public void findAll(User user) {
    14         userDao.findAll(user);
    15         System.out.println(otherProperty);
    16     }
    17 }

    第二步:修改配置文件,如下:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4        xmlns:context="http://www.springframework.org/schema/context"
     5        xsi:schemaLocation="http://www.springframework.org/schema/beans
     6                            http://www.springframework.org/schema/beans/spring-beans.xsd
     7                            http://www.springframework.org/schema/context
     8                            http://www.springframework.org/schema/context/spring-context.xsd">
     9         <context:annotation-config />
    10         <bean id="userService" class="com.justnow.service.impl.UserServiceImpl">
    11             <property name="otherProperty" value="利用property标签注入的值"/>
    12         </bean>
    13 
    14         <bean id="userDao10" class="com.justnow.dao.UserDao" />
    15 </beans>

    第三步:测试

     1     @Test
     2     public void test(){
     3         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     4         IUserService userService = (IUserService) context.getBean("userService");
     5         User user = new User();
     6         user.setId(1);
     7         user.setName("justnow");
     8         user.setMoney(1.0f);
     9         userService.findAll(user);
    10     }

    结果:

    该结果,与按名字实现自动装配的结果一致!

    场景二:标注在需要自动装配Bean引用的任意方法

    比如说,下面的方法:

    @Autowired
    pubilc void differentWay(UserDao userdao){
       this.userdao=userdao;    
    }

    该方法并不是set方法,但是通过注解实现自动装配userDao这个Bean

    场景三:标注在构造函数

    如下:

    1     @Autowired
    2     public UserServiceImpl(UserDao userDao){
    3         this.userDao = userDao;
    4     }

    场景四:直接标注属性,并删除setter方法

    在我们的开发过程中,利用这种方法实现自动装配,使用的非常频繁。

    第一步:修改UserServiceImpl实现类,在私有属性上添加注解,并删除setter方法

     1 public class UserServiceImpl implements IUserService {
     2     @Autowired
     3     private UserDao userDao;
     4 
     5     private String otherProperty;
     6 
     7     public void setOtherProperty(String otherProperty) {
     8         this.otherProperty = otherProperty;
     9     }
    10 
    11     public void findAll(User user) {
    12         userDao.findAll(user);
    13         System.out.println(otherProperty);
    14     }
    15 }

    测试下:

     @Autowired不会受限于private关键字。即使属性是私有的实例变量,它仍然可以被自动装配!

    自动装配,只是帮助我们不再编写<property>和<constructor-arg>元素,我们仍需要使用<bean>元素显示定义Bean。

    二、自动检测Bean

    这是Spring的另一种技巧,<context:component-scan>元素除了完成<context:annotation-config>一样的工作外,还允许Spring自动检测Bean和定义Bean。也就说,不再使用<bean>元素,Spring应用中的大多数Bean都能够实现定义和装配。

    使用方法如下:

    <context:component-scan

      base-package="com.justnow">

    </context:component-scan>

    <context:component-scan>元素会扫描指定的包及其所有自曝,并查找出能够自动注册为Spring Bean的类。base-package属性标识了<context:component-scan>元素所扫描的包。

    那么,<context:component-scan>又是如何知道哪些类需要注册为Spring Bean呢?

    2.1 使用注解,为自动检测标注Bean

    (1) @Component

    作用:把资源让spring管理。相当于在xml中配置一个bean

    属性:value:指定了bean的id。如果不指定value属性,默认bean的id是当前类的类名(首字母小写)。

    (2) @Controller @Service @Repository

    这三个注解都是针对第一个的衍生注解,他们的作用级属性都是一模一样。不过提供了更加明确的语义化。

    @Controller:一般用于表现层的注解。即SpringMVC中

    @Service:一般用于业务层的注解。

    @Repository:一般用于持久层的注解。

    (3) @Autowired

    这个注解相当于使用第一节中的autodetect类型的自动装配。首先尝试使用constructor进行自动装配。如果失败,再尝试使用byType进行自动装配。

    当使用该注解注入属性时,setter方法可以省略!

    2.2 过滤组件扫描

    如果出现接下来的需求,我们使用<context:component-scan>扫描了com.justnow,但是对于com.justnow.controller中的包,我们不希望被扫描到,此时,就需要使用<context:include-filter>和<context:exclude-filter>子元素来调整扫描的行为。

    (1) <context:include-filter>

    该元素还包括以下属性:type和expression,使用方式如下

    type和expression的

    第一种搭配:过滤器扫描使用指定注解所标注的那些类。通过expression属性指定要扫描的注解

    第二种搭配:过滤器扫描派生与(实现或者继承)expression属性所指定类型的那些类。

    第三种搭配:过滤器扫描与expression属性所指定的AspectJ表达式所匹配的那些类。

    第四种搭配:过滤器扫描类的名称与expression属性所指定的正则表达式所匹配的那些类。

    第五种搭配:使用自定义的org.springframework.core.type.TypeFilter实现类,该类由expression属性指定。

    举个例子:

    1     <context:component-scan base-package="com.justnow">
    2         <context:include-filter type="assignable" expression="com.justnow.service.IUserService"/>
    3     </context:component-scan>

    只扫描,在com.justnow包下实现com.justnow.service.IUSerService接口的类。

    (2) <context:exclude-filter>,为哪些类不需要注册为Spring Bean。

    如:

        <!--1、 配置 spring 创建容器时要扫描的包  -->
        <context:component-scan base-package="com.justnow">
            <!--制定扫包规则,不扫描@Controller 注解的 JAVA 类,其他的还是要扫描 -->
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
        </context:component-scan>

    即不扫描@Controller注解的java类,但是其他的还要扫描。

    参考:


    https://docs.spring.io/spring/docs/4.3.25.RELEASE/spring-framework-reference/htmlsingle/

    三、总结

    1、最小化Spring XML配置是通过自动装配和自动检测实现的。前者让我们不再依赖<property>和<constructor-org>元素,而后者可以解放为每个类创建Bean这个繁琐的过程。

    2、还有一种基于Java的Spring的配置没有总结,这种方法当然也非常实用。

  • 相关阅读:
    【C++】小心使用文件读写模式:回车(' ') 换行(' ')问题的一次纠结经历
    小记同学一次奇葩的DNS欺骗实验失败经历
    IE的BHO通过IHTMLDocument2接口获得网页源代码
    HTML5离线缓存攻击测试(二)
    HTML5离线缓存攻击测试
    PHP防止SQL注入的方法
    Linux系统环境变量的四个配置文件的关系
    CentOS 7 上搭建LNMP环境
    [Linux][Nginx][02]Config
    [Linux][Nginx][01]Install
  • 原文地址:https://www.cnblogs.com/justn0w/p/11503094.html
Copyright © 2020-2023  润新知