Spring IoC容器(三)注解

 Spring 除了支持通过XML形式配置Bean外,也支持通过注解的形式来配置Bean。需要简洁、易于维护和低耦合度场景下,注解是更好的选择;需要可读性强、可扩展性和分离关注点的场景下,XML是一个更好的选择。

方式

优点

缺点

注解

  1. 简洁易读:注解的名称和含义都比较直观,易于理解。
  2. 易于维护:当需要修改配置时,只需要修改相应的注解即可,不需要像XML那样要修改多个文件。
  3. 降低耦合度:通过自动布线(Autowired)可以减少代码之间的硬编码依赖,降低耦合度。
  1. 可能会破坏类的纯洁性:使用注解可能会将一些业务逻辑和配置逻辑混在一起,破坏类的纯洁性。
  2. 不易调试:当出现配置错误时,可能很难定位问题所在,因为配置信息都隐藏在注解中。

xml

  1. 易于阅读和编辑,可读性强:XML格式的配置文件结构清晰,易于阅读和编辑。可以更好地分离关注点,使得代码更加清晰易读。
  2. 可扩展性强:XML配置文件可以方便地扩展和定制化,满足不同的项目需求。
  1. 维护成本高:通常比注解方式更加复杂,需要更多维护成本。
  2. 代码耦合度高:需要硬编码配置信息,使得代码之间耦合度较高。
  3. 不够简洁:需要更多的文件和代码量。

表 注解与xml 形式配置Bean的优缺点

1 常用注解

1.1 @Configuration

是Spring中一个核心注解,用于应用程序的配置信息(类似于xml配置文件)。作用于类,被注解的类里面可以配置和管理Bean。AnnotationConfigApplicationContext可用来创建支持注解的上下文。其接受一个@Configuration注解的类型,在创建上下文时,其注解的类会被容器创建实例。被创建的实例可以像其他bean一样被容器管理及获取。

1.1.1 @ComponentScan

用于定位扫描Bean的位置。@ComponentScan(basePackages = "beans") 表示扫描beans包下的所有Bean。与@Configuration配合一起使用时,beans包下所有有注解Bean的类都会被容器注册为bean。

1.2 @Autowired、@Resource与@Inject

这三个注解功能类似,都是用于自动装配Bean。但是在Spring 5.1之后@Autowired 与 @Resource被废弃了,可以使用@Inject来代替。

 1.2.1 @Autowired

@Autowired 用于自动装配bean,有以下作用:

  1. 自动装配,当一个类中声明了@Autowired,Spring容器会自动寻找匹配(或创建)的Bean并注入到该类中。这大大简化了Bean的装配过程。
  2. 配置灵活,可标注在成员变量、方法或构造函数上。
  3. 可根据类型、字段名称(与bean的类型名称小写做匹配)及名称自动匹配(名称需要配合@Qualifier一起使用)。

还可以对集合类型及Map进行自动装配。把容器中符合的类型实例注入到集合中,或者将bean名作为key,bean实例作为value注入到Map中。

对于有多种同类型的Bean,如果使用@Autowired的字段名在这些bean中匹配不上,则会报错,这时可以在配置bean的地方,对其中一个bean加上@Primary 用来指定该类型的一个首要的bean。

public interface Mapper {
}

@Repository
public class OrderMapper implements Mapper{
    public OrderMapper() {
        System.out.println("OrderMapper实例化");
    }
}

@Repository
public class UserMapper implements Mapper{
    public UserMapper() {
        System.out.println("UserMapper实例化");
    }
}

@Service
public class OrderService {

    public OrderService() {
        System.out.println("实例化");
    }

    @Autowired
    private Mapper userMapper;
    @Autowired
    private Mapper orderMapper;
    @Autowired
    private List mappers;
    @Autowired
    private Map mapperMap;

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        OrderService service = context.getBean(OrderService.class);
        System.out.println(service);
    }

    @Override
    public String toString() {
        return "OrderService{" +
                "userMapper=" + userMapper +
                ", orderMapper=" + orderMapper +
                ", mappers=" + mappers +
                ", mapperMap=" + mapperMap +
                '}';
    }
}

@Configuration
@ComponentScan(basePackages = "beans")
public class SpringConfig {
    public SpringConfig() {
        System.out.println("SpringConfig实例化");
    }
}

1.2.2 @Qualifier

用于解决自动装配时的歧义问题,可以帮助指定要注入的确切Bean。可以用来指定Bean的名称及类型。注意:使用@Qualifier 指定类型时,必须确保所指定的类型是唯一的,否则仍会抛出异常。

public interface MyService {
}

@Configuration
@ComponentScan(basePackages = "beans.qualifier")
public class MyConfig {

    @Bean
    @Qualifier("service1")
    public MyService myService1() {
        return new MyService() {};
    }

    @Bean
    @Qualifier("service2")
    public MyService myService2() {
        return new MyService() {};
    }

}

@Controller
public class MyController {

    @Autowired
    @Qualifier("service1")
    private MyService service1;

    @Autowired
    @Qualifier("service2")
    private MyService service2;

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        System.out.println(context.getBean(MyController.class));
    }

    @Override
    public String toString() {
        return "MyController{" +
                "service1=" + service1 +
                ", service2=" + service2 +
                '}';
    }
}

1.2.3 @Autowired 被废弃的原因

1)保持与Java规范的一致性。@Autowired是Spring特有的注解,而@Inject是Java规范中的注解。(@Resource 被废弃也是因为这个原因,其是Java EE规范和Spring的一个注解,不是Java规范的注解)

2)处理多个匹配的依赖项时,如果没有明确指定依赖名称,Spring会抛出异常,这可能会导致代码的不稳定性。

3)类的成员变量如果使用了@Autowired,这个类必须交给Spring管理,否则该注解就会失效。

1.3 被废弃的注解

JSR 是Java依赖注入标准的规范,它提供了一种标准的依赖注入机制。其中有些注解可以代替Spring的某些注解。JSR-330中,像@Autowired 一样,有些注解已被Spring废弃,用JSR-330的注解代替(需要引入javax.inject包)。

Spring

JSR-330

@Autowired

@Inject

@Component

@Names/@ManagedBean

@Scope(“singleton”)

@Singleton

@Qualifier

@Qualifier/@Named

@Required

无,但是该注解在Spring 5.1后被废弃,Spring 5.1 引入构造函数注入和自定义InitializingBean接口来实现初始化逻辑来替换这个注解。

表 JSR330 可替换 Spring中的注解

2 @ComponentScan组件扫描

用于指定Spring在哪些包中搜索被@Component(报告@Service、@Controller等)注解的类,并将它们自动注册为Spring容器中的Bean。还可以指定一些属性来自定义扫描行为:

basePackages/value

要扫描的包名,接受字符串数组类型。

basePackageClasses

要扫描的包中的一个类,将扫描该类所在包及其子包。

includeFilters

用于指定只包含满足特定条件的组件。是一个Filter类型数组,每个Filter对象包含type、classes属性和pattern属性等,classes属性是一个包含需要过滤的类的数组。pattern是指定匹配的正则表达式。

excludeFilteres

用于指定需要排除的组件。

useDefaultFilters

是一个bool类型,用于指定是否需要使用Spring的默认扫描规则。规则包括被@Component、@Repository、@Service、@Controller或者已经声明过@Component自定义注解标记的注解。

nameGenerator

自定义Bean的名称的Generator。

scopeResolver

自定义作用域的Generator。

scopedProxy

用于支持作用域Bean的属性,决定了是否需要创建代理对象。

resourcePattern

字符串类型,用于指定要扫描的资源模式的正则表达式。

lazyInit

bool类型,是否懒加载。

表 @ComponentScan 的属性

Spring IoC容器(三)注解_第1张图片

图 @ComponentScan注解的结构图

2.1 @Filter

@Filter注解是@ComponentScan内部定义的注解。用来定义过滤类型。其属性type 是FilterType 类型的枚举。

annotation

默认值。指定注解,用于过滤被特定注解标注的类。

assignable

指定类型,用于过滤特定类型的类。

aspectj

Aspect语法指定。

regex

正则表达式指定,用于过滤满足表达式的类名。

custom

自定义规则及过滤逻辑,通过实现ApplicationContextAware接口并覆盖getbeanDefinitionNames方法来指定自己的过滤规则。

表 FilterType的枚举值

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent {
}

@Configuration
@ComponentScan(lazyInit = true,basePackages = "scan.beans", includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {MyComponent.class})})
public class ScanConfig {
}

@MyComponent
public class UserService {

    public UserService() {
        System.out.println("UserService实例化");
    }

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(ScanConfig.class);
        UserService userService = context.getBean(UserService.class);
        System.out.println(userService);
    }

}

你可能感兴趣的:(Spring,java,spring,依赖倒置原则)