zoukankan      html  css  js  c++  java
  • Spring学习(五)Spring 基于注解装配Bean

    Spring 学习目录

    Spring 基于注解装配Bean

    前言

    ​ 在 Spring 中,尽管可以使用 XML 配置文件实现 Bean 的装配工作,但如果应用中 Bean 的数量较多,会导致 XML 配置文件过于臃肿,从而给维护和升级带来一定的困难。

    ​ Java 从 JDK 5.0 以后,提供了 Annotation(注解)功能,Spring 2.5 版本开始也提供了对 Annotation 技术的全面支持,我们可以使用注解来配置依赖注入。

    ​ Spring 默认不使用注解装配 Bean,因此需要在配置文件中添加 <context:annotation-config/>,启用注解。

    • 注解:就是一个类,使用@注解名称
    • 开发中:使用注解 取代 xml配置文件。

    什么是注解

    Annontation是Java5开始引入的新特征,中文名称叫注解

    ​ 它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
      Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。

    注解的用处:

    1、生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等
    2、跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2依赖注入,未来java开发,将大量注解配置,具有很大用处;
    3、在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

    更多注解信息点击这里-JAVA 注解的基本原理 - Single_Yam - 博客园 (cnblogs.com)

    为什么要使用注解装配Bean

    传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事物,这么做有两个缺点:

    1. 如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大;如果按需求分开.xml文件,那么.xml文件又会非常多,总之这将导致配置文件的可读性与可维护性变得很低。
    2. 在开发中在.java文件和.xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率。

    为了解决这两个问题,Spring引入了注解,通过"@XXX"的方式,让注解与Java Bean紧密结合,大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。

    使用Spring注解

    0.启用组件扫描

    1)使用XML进行扫描

    <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:component-scan base-package="com.spring.learn2" />
    </beans>
    

    配置属性<context:component-scan base-package="com.spring.learn2" />

    其中`base-package

    2) @ComponentScan注解启用了组件扫描

    package com.spring.learn2.config;
    
    import org.springframework.context.annotation.ComponentScan;
    
    @ComponentScan
    public class BeanConfig {}
    
    package com;
    
    import com.spring.learn2.config.BeanConfig;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class MainApp {
        public static void main(String[] args) {
            ApplicationContext applicationContext =
                    new AnnotationConfigApplicationContext(BeanConfig.class);
    
            String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
            for (String beanName : beanDefinitionNames) {
                System.out.println("beanName: " + beanName);
            }
        }
    }
    
    

    运行效果

    beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
    beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
    beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
    beanName: org.springframework.context.event.internalEventListenerProcessor
    beanName: org.springframework.context.event.internalEventListenerFactory
    beanName: beanConfig
    

    除了 spring 本身注册的一些 bean 之外,可以看到最后一行,已经将 BeanConfig 这个类注册进容器中了。

    创建一个配置类,在配置类上添加 @ComponentScan 注解。该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 <context:component-scan>

    类BeanConfig通过Java代码定义了Spring的装配规则。观察可知,BeanConfig类并没有显式地声明任何bean,只不过它使用了@ComponentScan注解,这个注解能够在Spring中启用组件扫描

    如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包。因为BeanConfig类位于com.spring.learn2.config包中,因此Spring将会扫描这个包以及这个包下的所有子包,查找带有@Component注解的类。这样的话,就能发现使用了注解的类,并且会在Spring中自动为其创建一个Bean

    3)指定要扫描的包

    (使用@ComponentScan 的 valule 属性来配置)

    @ComponentScan(value = "com.spring.learn2")
    public class BeanConfig {
    
    }
    
    excludeFilters 和 includeFilters 的使用
    使用 excludeFilters 来按照规则排除某些包的扫描。
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.ComponentScan.Filter;
    import org.springframework.context.annotation.FilterType;
    import org.springframework.stereotype.Controller;
    
    @ComponentScan(value = "com.spring.learn2",
            excludeFilters = {@Filter(type = FilterType.ANNOTATION,
            value = {Controller.class})})
    public class BeanConfig {
    
    }
    

    excludeFilters 的参数是一个 Filter[] 数组,然后指定 FilterType 的类型为 ANNOTATION,也就是通过注解来过滤,最后的 value 则是Controller 注解类。

    ​ 配置之后,在 spring 扫描的时候,就会跳过 com.spring.learn2 包下,所有被 @Controller 注解标注的类

    使用 includeFilters 来按照规则只包含某些包的扫描。
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.ComponentScan.Filter;
    import org.springframework.context.annotation.FilterType;
    import org.springframework.stereotype.Controller;
    
    @ComponentScan(value = "com.spring.learn2", includeFilters = {@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})})
    public class BeanConfig {
    
    }
    

    spring 默认会自动发现被 @Component、@Repository、@Service 和 @Controller 标注的类,并注册进容器中。要达到只包含某些包的扫描效果,就必须将这个默认行为给禁用掉(在 @ComponentScan 中将 useDefaultFilters 设为 false 即可)。

    @ComponentScan 的 useDefaultFilters 属性,该属性默认值为 true。

    1. 定义Bean@Component

    需要在类上使用注解@Component,该注解的value属性用于指定该bean的id值。

    @Component(value = "role")
    public class Role {
        private Long id;
        private String roleName;
        private String note;
    }
    

    2. Bean的作用域@Scope

    需要在类上使用注解@Scope,其value属性用于指定作用域。默认为singleton。

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    
    @Scope("prototype")
    @Component("RoleService")
    public class RoleServiceImpl implements RoleService {
        ...
    }
    
    

    3. 基本类型属性注入@Value

    需要在属性上使用注解@Value,该注解的value属性用于指定要注入的值。
    使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。

    package com.spring.learn2;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component(value = "role")
    public class Role {
        @Value("1")
        private Long id;
        @Value("role_name_1")
        private String roleName;
        @Value("role_note_1")
        private String note;
    }
    

    4.按类型注入域属性@Autowired

    @Autowired是spring的注解

    需要在域属性上使用注解@Autowired,该注解默认使用按类型自动装配Bean的方式。
    使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。

    package com.spring.learn2;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    
    @Scope("prototype")
    @Component("RoleService")
    public class RoleServiceImpl implements RoleService {
        @Autowired
        private Role role;
    
        /**** setter and getter ****/
        public Role getRole() {
            return role;
        }
    
        public void setRole(Role role) {
            this.role = role;
        }
    }
    
    

    5. 按名称注入域属性@Autowired与@Qualifier

    需要在域属性上联合使用注解@Autowired与@Qualifier。

    @Qualifier的value属性用于指定要匹配的Bean的id值。同样类中无需setter,也可加到setter上。

    package com.spring.learn2;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    
    @Scope("prototype")
    @Component("RoleService")
    public class RoleServiceImpl implements RoleService {
        @Autowired(required =false)
     	@Qualifier("role")
        private Role role;
    
        /**** setter and getter ****/
        public Role getRole() {
            return role;
        }
    
        public void setRole(Role role) {
            this.role = role;
        }
    }
    
    

    @Autowired还有一个属性required,默认值为true,表示当匹配失败后,会终止程序运行。若将其值设置为false,则匹配失败,将被忽略,未匹配的属性值为null。

    6. 域属性注解@Resource

    @Resource是java自带的注解

    Spring提供了对JSR-250规范中定义@Resource标准注解的支持。@Resource注解既可以按名称匹配Bean,也可以按类型匹配Bean。使用该注解,要求JDK必须是6及以上版本。

    1. 按类型注入域属性

    @Resource注解若不带任何参数,则会按照类型进行Bean的匹配注入。

    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    
    @Component("RoleService")
    public class RoleServiceImpl implements RoleService {
        @Resource
        private Role role;
    
        /**** setter and getter ****/
        public Role getRole() {
            return role;
        }
    
        public void setRole(Role role) {
            this.role = role;
        }
    }
    

    2. 按名称注入域属性

    @Resource注解指定其name属性,则name的值即为按照名称进行匹配的Bean的id。

    package com.spring.learn2;
    
    
    import org.springframework.stereotype.Component;
    import javax.annotation.Resource;
    
    
    @Component("RoleService")
    public class RoleServiceImpl implements RoleService {
        @Resource(name="role")
        private Role role;
    
        /**** setter and getter ****/
        public Role getRole() {
            return role;
        }
    
        public void setRole(Role role) {
            this.role = role;
        }
    }
    
    

    7. Bean的生命始末@PostConstruct与@PreDestroy

    在方法上使用@PostConstruct,与原来的init-method等效。在方法上使用@PreDestroy,与destroy-method等效。

    package com.spring.learn2;
    
    
    import org.springframework.stereotype.Component;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    import javax.annotation.Resource;
    
    
    @Component("RoleService")
    public class RoleServiceImpl implements RoleService {
        @Resource(name="role")
        private Role role;
    
        @PostConstruct
        public void init(){
            System.out.println("Bean初始化后执行");
        }
    
        @PreDestroy
        public void destroy(){
            System.out.println("Bean销毁前执行");
        }
    
        /**** setter and getter ****/
        public Role getRole() {
            return role;
        }
    
        public void setRole(Role role) {
            this.role = role;
        }
    }
    
    

    Spring 中常用的注解

    @Component取代<bean class="">

    @Component("id") 取代 <bean id="" class="">

    web开发,提供3个@Component注解衍生注解(功能一样)取代<bean class="">

    @Repository :dao层 。

    @Service:service层 。

    @Controller:web层。

    @Component

    可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    @Component(value = "role")
    public class Role {
        @Value("1")
        private Long id;
        @Value("role_name_1")
        private String roleName;
        @Value("role_note_1")
        private String note;
    }
    
    • 注解@Component代表Spring IoC会把这个类扫描生成Bean实例,而其中的value属性代表这个类在Spring中的id,这就相当于XML方式定义的Bean的id,也可以简写成@Component("role"),甚至直接写成@Component,对于不写的,Spring IoC容器就默认类名,但是以首字母小写的形式作为id,为其生成对象,配置到容器中。
    • 注解@Value代表的是值的注入,这里只是简单注入一些值,其中id是一个long型,注入的时候Spring会为其转化类型。

    @Repository

    用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

    @Service

    通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

    @Controller

    通常作用在控制层(如 Struts2 的 Action、SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

    @Autowired

    自动装配

    ​ 通过学习Spring IoC容器,我们知道Spring是先完成Bean的定义和生成,然后寻找需要注入的资源。也就是当Spring生成所有的Bean后,如果发现这个注解,他就会在Bean中查找,然后找到对应的类型,将其注入进来,这样就完成依赖注入了。

    ​ 所谓自动装配技术是一种由Spring自己发现对应的Bean,自动完成装配工作的方式,它会应用到一个十分常用的注解@Autowired上,这个时候Spring会根据类型去寻找定义的Bean然后将其注入,这里需要留意按类型(Role)的方式。

    ​ 可以应用到 Bean 的属性变量、属性的 setter 方法、非 setter 方法及构造函数等,配合对应的注解处理器完成 Bean 的自动配置工作。默认按照 Bean 的类型进行装配。

    • 示例

      role

      package com.spring.learn2;
      
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.stereotype.Component;
      
      @Component(value = "role")
      public class Role {
          @Value("1")
          private Long id;
          @Value("role_name_1")
          private String roleName;
          @Value("role_note_1")
          private String note;
      
          public Long getId() {
              return id;
          }
      
          public void setId(Long id) {
              this.id = id;
          }
      
          public String getRoleName() {
              return roleName;
          }
      
          public void setRoleName(String roleName) {
              this.roleName = roleName;
          }
      
          public String getNote() {
              return note;
          }
      
          public void setNote(String note) {
              this.note = note;
          }
      }
      

      RoleService

      package com.spring.learn2;
              
      public interface RoleService {
          public void printRoleInfo();
      }
      
      package com.spring.learn2;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Component;
        
      @Component("RoleService")
      public class RoleServiceImpl implements RoleService {
          @Autowired
          private Role role;
        
          @Override
          public void printRoleInfo() {
              System.out.println("id =" + role.getId());
              System.out.println("roleName =" + role.getRoleName());
              System.out.println("note =" + role.getNote());
          }
        
          /**** setter and getter ****/
          public Role getRole() {
              return role;
          }
        
          public void setRole(Role role) {
              this.role = role;
          }
      }
        
      

      MainApp

      package com;
      
      
      import com.spring.learn2.RoleService;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class MainApp {
          public static void main(String[] args) {
              ApplicationContext ctx = new ClassPathXmlApplicationContext("Beans.xml");
              RoleService uc = (RoleService) ctx.getBean("RoleService");
              uc.printRoleInfo();
          }
      }
      
      

      Beans.xml

      扫描含有注解类

      <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:component-scan base-package="com.spring.learn2" />
      </beans>
      

      ​ 这里的@Autowired注解,表示在Spring IoC定位所有的Bean后,这个字段需要按类型注入,这样IoC容器就会寻找资源,然后将其注入。。比如代码Role和代码RoleServiceImpl的两个Bean,假设将其定义,那么Spring IoC容器会为它们先生成对应的实例,然后依据@Autowired注解,按照类型找到定义的实例,将其注入。

       IoC容器有时候会寻找失败,在默认的情况下寻找失败它就会抛出异常,也就是说默认情况下,Spring IoC容器会认为一定要找到对应的Bean来注入这个字段,有些时候这并不是一个真实的需要,比如日志,有时候我们会觉得这是可有可无的,这个时候可以通过@Autowired的配置项required来改变它,比如@Autowired(required=false)。

      ​ 正如之前所谈到的在默认情况下是必须注入成功的,所以这里的required的默认值为true。当把配置修改为了false时,就告诉Spring IoC容器,假如在已经定义好的Bean中找不到对应的类型,允许不注入,这样也就没有了异常抛出,只是这样这个字段可能为空,读者要自行校验,以避免发生空指针异常。在大部分的情况下,都不需要这样修改。
      ​ @Autowired除可以配置在属性之外,还允许方法配置,常见的Bean的setter方法也可以使用它来完成注入。

    @Resource

    ​ 作用与 Autowired 相同,区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 实例名称进行装配。

    ​ @Resource 中有两个重要属性:name 和 type。

    ​ Spring 将 name 属性解析为 Bean 的实例名称,type 属性解析为 Bean 的实例类型。如果指定 name 属性,则按实例名称进行装配;如果指定 type 属性,则按 Bean 类型进行装配。如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。

    ​ 另外要注意,@Resource是java自带的注解,不是Spring中的注解。@Resource注解完整的包路径为

    import  javax.annotation.Resource;
    

    示例

    @Resource(name = "userServiceImpl")
    private UserService userService;
    

    @Qualifier

    与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。

     @Autowired
     @Qualifier("userServiceImp")
     private UserSerevice userService;
    

    @Service@Controller 这些注解要放在接口的实现类上,而不是接口上面。

    @Autowired@Resource是用来修饰字段,构造函数,或者设置方法,并做注入的。

    @Service@Controller@Repository@Component则是用来修饰类,标记这些类要生成bean。

    注解使用前提,添加命名空间,让spring扫描含有注解类

    示例

    Beans.xml

    <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:component-scan base-package="com.spring.learn1" />
    </beans>
    

    UserDao

    package com.spring.learn1;
    
    public interface UserDao {
        /**
         * 输出方法
         */
        public void outContent();
    }
    

    UserDaoImpl

    package com.spring.learn1;
    
    import org.springframework.stereotype.Repository;
    @Repository("userDao")
    public class UserDaoImpl implements UserDao {
        @Override
        public void outContent() {
            System.out.println("dao方法");
        }
    }
    
    package com.spring.learn1;
    
    public interface UserService {
        /**
         * 输出方法
         */
        public void outContent();
    }
    

    UserServiceImpl

    package com.spring.learn1;
    
    import javax.annotation.Resource;
    import org.springframework.stereotype.Service;
    @Service("userService")
    public class UserServiceImpl implements UserService{
    
        @Resource(name="userDao")
        private UserDao userDao;
    
        public UserDao getUserDao() {
            return userDao;
        }
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
        @Override
        public void outContent() {
            userDao.outContent();
            System.out.println("service");
        }
    }
    

    UserController

    package com.spring.learn1;
    
    import javax.annotation.Resource;
    import org.springframework.stereotype.Controller;
    @Controller("userController")
    public class UserController {
        @Resource(name = "userService")
        private UserService userService;
        public UserService getUserService() {
            return userService;
        }
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
        public void outContent() {
            userService.outContent();
            System.out.println("content");
        }
    }
    

    MainApp

    package com;
    
    
    import com.spring.learn1.UserController;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainApp {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("Beans.xml");
            UserController uc = (UserController) ctx.getBean("userController");
            uc.outContent();
        }
    }
    
    

    运行时以下错误

    org.springframework.context.support.AbstractApplicationContext refresh
    
    警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController' defined in file [。。。]: Post-processing of merged bean definition failed; nested exception is java.lang.NoSuchMethodError: javax.annotation.Resource.lookup()Ljava/lang/String;
    Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController' defined in file [。。。]: Post-processing of merged bean definition failed; nested exception is java.lang.NoSuchMethodError: javax.annotation.Resource.lookup()Ljava/lang/String;
    。。。。
    Caused by: java.lang.NoSuchMethodError: javax.annotation.Resource.lookup()Ljava/lang/String;
    

    检查发现不存在javax.annotation这个包

    在pom.xml文件中引入

    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>javax.annotation-api</artifactId>
        <version>1.3.1</version>
    </dependency>
    

    运行如下

    dao方法
    service
    content
    

    @Resource vs @Autowired

    @Resource的装配顺序如下:

    1. @Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配;
    2. 指定了name或者type则根据指定的类型去匹配bean;
    3. 指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错。

    然后,区分一下@Autowired和@Resource两个注解的区别:

    1. @Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配
    2. @Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了

    Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。

    总结一下:

    @Resource根据name和type,是先Name后Type,@Autowired是Type,一般情况下我们最好使用@Resource。

    ​ 文中详细讲解了@Service、@Autowired、@Resource和@Qualifier的用法,其中重点讲述了@Autowired、@Resource的区别,那么对于@Component、@Repository、@Controller这3个注解,文中也就开头提到,这3个注解其实和@Service一个含义,只是我们在写代码时,会进行分层,比如DAO层、Service层、Action层,分别可以用@Repository、@Service、@Controller表示,其实也就字面含义不一样,效果其实是一样的,然后@Component可以作用在任何层次。所以看起来有7个注解,其实你可以理解只有4个。

  • 相关阅读:
    【CANoe基础】CANoe常用操作
    ZedGraph控件横纵坐标显示中文名(转)
    Winforn中设置ZedGraph曲线图的属性、坐标轴属性、刻度属性(转)
    c# 访问sqlite资源
    混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该程序集。
    ABP框架资源
    vue新建项目一直在downloading template转,最后超时
    vscode(实验)--ABP框架 .net core 版本的安装与运行(vue模板)(转)
    安装-打开-运行-ABP框架(asp.net core 2.X+Vue)运行前端(转)
    VSCode打开Visual Studio的ABP框架项目(转)
  • 原文地址:https://www.cnblogs.com/qs315/p/15702981.html
Copyright © 2011-2022 走看看