Spring注解s

  • @Autowired是什么?
    依赖注入的地方,前提是被注入的对象和注入的对象都要在Spring中注册为bean(利用注解@Configuration)
public interface HelloWorldService {
    void sayHi(String name);
}
public class HelloWorldServiceImpl implements HelloWorldService {

    public void sayHi(String message) {
        System.out.println(message);
    }
}
public class HelloWorldServiceClient {

    @Autowired
    private HelloWorldService helloWorld;

    public void showMessage() {
        helloWorld.sayHi("Hello world!");
    }
}
  • 一个小例子
    @Configuration使用Java类进行配置,该类还需要负责在main方法中开启Spring容器。
    每个@Configuration注解的类都会在Spring容器中注册成一个Bean,并且Spring会使用CGLib对其进行动态代理,这样可以管理不同Bean不同的声明周期和Bean的代理对象;
    Spring容器可以有多个@Configuration注解的类,这点从构造函数中就可以看出来,public AnnotationConfigApplicationContext(Class... componentClasses);可以输入多个类。
    @Bean的方法创建并返回了对应的bean对象,只会调用一次并且缓存创建的对象
@Configuration
public class AppRunner {

    @Bean
    public HelloWorldService createHelloWorldService() {
    }

    @Bean
    public HelloWorldServiceClient createClient() {
        return new HelloWorldServiceClient();
    }

    public static void main(String... strings) {
        AnnotationConfigApplicationContext context =
                                new AnnotationConfigApplicationContext(AppRunner.class);
        HelloWorldServiceClient bean = context.getBean(HelloWorldServiceClient.class);
        bean.showMessage();
    }

}
  • AnnotationConfigApplicationContext是啥玩意?
    AnnotationConfigApplicationContext实现了ApplicationContext接口,代表Spring容器,实现了实例化、配置、组装等功能,输入为注解的类。

  • 输出
    Hello world!

  • @ComponentScan
    之前我们自己在@Configuration注解的类中用@Bean注解要创建Bean的方法,而如果我们使用@ComponentScan和@Configuration,Spring就可以自动创建类。

  • @Import
    除了在AnnotationConfigApplicationContext的构造函数中输入多个@Configuration注解的类之外,还可以使用@Import在其他配置类中加入其他配置类,这种方法更加模块化,引用的方式呈现树状,而不是直接输入多个配置类的平面状。
    可以将@Import注解跟Java中引包的import关键字对比下,一样的。
    下图中AppConfig类用@Import引入了其他配置类DataSourceConfig,AnnotationConfigApplicationContext初始化的时候只需要引入AppConfig类即可。注意DataSourceConfig同样需要使用@Configuration注解。


  • @Bean
    @Bean注解是一个方法注解,跟XML配置中的元素一样。
    名字:实例有一个默认名字也就是方法的名字calculator,在多个实例的时候,可能可以用这个解决混淆(不知道注入哪个实例)的问题。也可以自行定义实例的名字@Bean(name = "aname")。同name,@Qualifier也可以定义“名字”。
    要在注入点对上,需要将注入的属性名字定义为方法的名字,或者注入点、setter也加上@Qualifier。

  @Bean
  Calculator calculator() {
      return new Calculator();
  }

参数:
name:名字,默认是方法的名字。一般用在同一个类有多个实例的时候,需要为不同的实例命名,在注入点的地方需要加入@Qualifier注解选择对应的类。
autowire:注入类型
Autowire.NO:默认值,需要在注入点使用@Autowired。
Autowire.BY_TYPE:Spring会根据类型扫描bean的属性并用setter方法注入,所以属性不用使用@Autowired注解,非常简洁,但是也容易看不懂,因为没有明示注入点。
Autowire.BY_NAME:注入点需要同时使用@Qualifier和@Autowired两个注解。
initMethod/destroyMethod:

  • @Autowired
    @Autowired用来定义注入点,除了注解在字段上,还可以注解在方法上,之后Spring会运行这个方法,输入的参数是对应的Bean。
    @Autowired有三种注入方法是,字段、setter、构造器等,从Spring4.3之后,构造器可以不用使用@Autowired,会隐式地注入。
  @Autowired
  public void configure(GreetingService greetingService, LocalDateTime appServiceTime) {
      greetingFormat = String.format("%s. This app is running since: %s%n", greetingService.getGreeting(""),
              appServiceTime.format(DateTimeFormatter.ofPattern("YYYY-MMM-d")));
  }
  • @Inject
    @Inject同@Autowired都是用来定义注入点,只不过前者是JSR 330's规范为依赖注入定义的注解,而后者是Spring自己的注解

  • @Primary
    可以解决ambiguity的问题,当有多个同类型的Bean的时候,会首先使用@Primary注解的Bean。

  • ambiguity
    1、注入的属性名字使用默认名字,也就是@Bean注解的方法的名字

Bean类
        @Autowired
        private ServiceBean serviceBean2;

Config类
        @Bean
        public ServiceBean serviceBean2 () {
            return new ServiceBean("Service Bean 2");
        }

2、@Bean类型注入(Autowire.BY_TYPE)时同一个类有两个实例
在setter参数中加上@Qualifier("serviceBean2") 注解,也可以在setter和bean两个地方都加上@Qualifier("serviceBean2") 注解

bean类
        public void setServiceBean (@Qualifier("serviceBean2") ServiceBean serviceBean) {
            this.serviceBean = serviceBean;
        }

3、使用@Qualifier注解,可以只在注入的地方用,也可以在Bean定义和注入的地方用

Bean类
        @Autowired
        @Qualifier("serviceBean2")
        private ServiceBean serviceBean;

4、使用@Resource注解
@Resource用在注入点,相当于@Qualifier和Autowired的组合


5、@Inject类似于@Autowired,因此也可以使用@Autowired加上@Qualifier
6、@Named类似于@Qualifier,因此也可以使用@Inject和@Named
7、@Primary可以指定在有多个bean的时候优先使用哪个
8、Spring 4.x具有泛型的注入能力,如果类型相同会根据具体的泛型进行注入,类型相同泛型不同不会引起NoUniqueBeanDefinitionException异常。

  • @DependsOn
    Spring除了注入对象先于被注入对象加载之外,并不能保证加载的顺序。@DependsOn可以使得别的对象先加载,再加载当前的类。
    eventPublisherBean依赖eventListenerBean,因此eventListenerBean会先加载。
  @Bean
  @DependsOn("eventListenerBean")
  public EventPublisher eventPublisherBean() {
      return new EventPublisher();
  }

  @Bean
  public EventListener eventListenerBean() {
      return new EventListener();
  }
  • 懒加载
    @Lazy with @Bean (or @Lazy with @Component):
    应用启动的时候不加载,直到使用的时候
    @Lazy with @Autowired:
    要注入的类加载的时候不加载,直到使用的时候
    原理:
    在一开始的时候用的是Proxy,用到的时候才去用真正的类

  • @Scope
    和@Bean、@Conponent注解一起使用。singleton表示Spring容器中只有一个,用在一些无状态的场合,比如Service、DAO、Controller等,而prototype每次都返回一个新的,且容器不再记录这个Bean,因此PreDestroy对于这类bean是不会调用的,用在一些有状态的场合,比如购物车、request、session等。

  • @ComponentScan
    需要和@Configuration一起搭配使用,用来指定要扫描的包,然后使用@Configuration、@Component、@Controller、@Repository、@Service定义Bean,其中@Component最重要,其他都是@Component的增强版而已,它们可以更好地结合切面以及今后的功能。
    这些注解都没有使用@Inherited,意味着这些注解不会作用到子类上。
    @ComponentScan(basePackageClasses = {OnlineOrderClient.class, OnlineOrderService.class})表示扫描OnlineOrderClient.class和OnlineOrderService.class这两个类所在的包。
    过滤

@ComponentScan(includeFilters = @ComponentScan.Filter(
        type = FilterType.ASSIGNABLE_TYPE, classes = {OrderService.class}))
  • @Component和@Configuration的不同
    @Configuration会使用CGLib代理,调用anotherBean每次都返回同一个bean,而@Component每次调用anotherBean每次都返回新的bean。建议仅在@Configuration的类中使用@Bean


  • 注入容器
    可以使用, , , and 等XML标签,再Java代码中可以直接定义

    @Bean
    public String[] fruits() {
        return new String[]{"apple", "banana", "orange"};
    }

    private static class TestBean {
        @Autowired
        private String[] fruits;

        @PostConstruct
        public void postConstruct() {
            System.out.println(Arrays.toString(fruits));
        }
    }

多个对象注入一个容器对象

@Component
class SavingAccount implements Account {
    @Override
    public String toString() {
        return "SavingAccount";
    }
}

@Component
class CheckingAccount implements Account {
    @Override
    public String toString() {
        return "CheckInAccount";
    }
}

@Component
class FixedDepositAccount implements Account {
    @Override
    public String toString() {
        return "FixedDepositAccount";
    }
}

    private static class TestBean {
        @Autowired
        private List accounts;

        @PostConstruct
        public void init() {
            System.out.println(accounts);
        }
    }

使用@Qualifier可以限定注入容器的元素,而不是全部

@Component
@Qualifier("basicAccount")
class SavingAccount implements Account {
    @Override
    public String toString() {
        return "SavingAccount";
    }
}

使用@Order可以按照顺序注入容器

  • 循环依赖
    循环依赖就是两个bean都想通过构造器注入彼此。
    最简单可以通过setter注入解决,但这样就不能通过构造器注入了,构造器注入可以将字段定义为final。
    @Lazy可以解决循环依赖,使用@Lazy的A会先用代理替代,这个代理初始化的时候不会要求实例化B,这样循环的链条就断了。

  • 依赖检查
    检查是否有对象没有注入
    一般在@PostConstruct的方法中检查对应的对象是否为null

  • @Component和@Bean的区别
    @Bean更加灵活,不用也不能注解在Bean的类上(也就是解耦了bean实例化和类定义),注解在实例化Bean的方法里面。

你可能感兴趣的:(Spring注解s)