springboot2.x入门(一)

控制反转(IoC)

控制反转是spring框架的两个核心理念之一。
因为SpingBoot是基于注解开发的Spring IoC,所以我们使用全注解的方式来了解Spring IoC技术。
IoC是一种通过描述来创建或者获取对象的技术。

什么是Bean

在Spring中,Bean是指交给SpringIoC容器管理的对象,一般来说,该对象是单例的。

IoC容器

基本功能:通过描述来管理Bean,包括发布和获取Bean;通过描述来完成Bean之间的依赖关系。在Spring中,他要求所有的IoC容器都需要实现接口BeanFactory,它是一个顶级接口。
我们了解一下BeanFactory的源码:

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    boolean containsBean(String var1);

    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;

    String[] getAliases(String var1);
}

这段代码中,有多个getBean方法,这也是IoC容器最重要的方法之一,这里有按类型(by type)从容器中获取bean,有按名称(by name)获取bean的。这对我们理解后面的依赖注入(Depedency Injection,DI)是十分重要的。
isSingleton方法判断Bean是否在Spring IoC中为单例,默认情况下,Bean都是以单例存在的。也就是说getBean方法返回的是同一个对象。与isSingleton方法相反,isPrototype方法,如果它返回true,那么使用getBean方法获取对象的时候,Spring IoC会创建一个新的Bean返回给调用者。
由于BeanFactory的功能不够强大,Spring在BeanFactory的基础上,还设计了一个更加高级的接口ApplicationContext,它是BeanFactory的子接口之一,我们使用的大部分SpringIoc容器都是ApplicationContext接口的实现类。

一个基于注解的IoC容器-AnnotationConfigApplicationContext

为了学习Spring Boot装配和获取Bean,来看代码:
先创建一个User类

public class User {

    private Long id;
    private String name;
    private int age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

然后写一个简单的配置文件

@Configuration
public class AppConfig {
    @Bean(name = "user")
    public User initUser() {
        User user = new User();
        user.setAge(12);
        user.setId(100L);
        user.setName("java");
        return user;
    }
}

最后通过AnnotationConfigApplicationContext来获取这个Bean

public class  IoCTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        User user = ctx.getBean(User.class);
        System.out.println(user.getAge());
        System.out.println(user.getId());
        System.out.println(user.getName());
    }
}

控制台打印了
12
100
java
显然,通过这种方式,代码将AppConfig传递给了AnnotationConfigApplicationContext的构造方法,这样它就能读取配置,然后将配置里面的Bean装配到IoC容器中。

装配你的Bean

在Spring中,可以通过xml或者注解装配Bean到IoC容器中,而SpringBoot是基于注解的方式。

通过扫描装配你的Bean

如果使用@Bean注解装配多个Bean时,就会比较麻烦,Spring提供了扫描Bean到IoC容器中,@Component是表明哪个类被扫描到IoC容器中,@ComponentScan则是标明采用何种策略去扫描装配Bean。
这里我们改造一下之前的代码,将User类放到config包下:

package com.awa.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("user")
public class User {

    @Value("10")
    private Long id;
    @Value("java")
    private String name;
    @Value("18")
    private int age;

}

这里的注解@Component表明这个类将被Spring IoC容器装配,其中配置“user”将作为Bean的名称,如果不指定这个字符串,那么IoC容器会把类名称的第一个字母小写,其他不变作为Bean的名称。注解@Value则是指定具体值,是的SpringIoC给予对应属性注入对应值。为了让Spring IoC容器装配这个类,需要改造AppConfig,

package com.awa.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class AppConfig {

}

这里加入了@Configuration注解,它会扫描AppConfig当前类所在的包和子包,通常情况下,User类不应该放到config包下,所以使用@ComponentScan自定义扫描路径。首先看一下@ComponentScan的源码:


package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
	// 定义扫描的包
    @AliasFor("basePackages")
    String[] value() default {};
	// 定义扫描的包
    @AliasFor("value")
    String[] basePackages() default {};
	// 定义扫描的类
    Class<?>[] basePackageClasses() default {};
	// Bean name生成器
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
	// 作用域解析器
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
	// 作用域代理模式
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
	// 资源匹配模式
    String resourcePattern() default "**/*.class";
	// 是否启用默认的过滤器
    boolean useDefaultFilters() default true;
	// 当满足过滤器的条件时扫描
    ComponentScan.Filter[] includeFilters() default {};
	// 档不满足过滤器的条件是扫描
    ComponentScan.Filter[] excludeFilters() default {};
	// 是否延迟初始化
    boolean lazyInit() default false;
	// 定义过滤器
    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
    	// 过滤器类型,可以按注解类型或者正则表达式等过滤
        FilterType type() default FilterType.ANNOTATION;
		// 定义过滤的类
        @AliasFor("classes")
        Class<?>[] value() default {};
		// 定义过滤的类
        @AliasFor("value")
        Class<?>[] classes() default {};
		// 匹配方式
        String[] pattern() default {};
    }
}

首先可以通过配置项basePackages定义扫描的包名,在没有定义情况下,它只会扫描当前包和其子包,可以通过basePackageClasses定义扫描的类;其中还有includeFIlters和excludeFilters,他们都需要一个注解@Filter去定义,他只有一个type类型。
修改AppConfig中的注解为
@ComponentScan(“com.awa.*”)或@ComponentScan(basePackages = {“com.awa.pojo”})或@ComponentScan(basePackageClasses = {User.class})。
有时候我们只需要包里面的一部分类被装配,而不是整个包里的所有类。例如现在有个UserService类,为了将它标注为服务类,需要注解@Service,该标准注入了@Component,

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

所以在默认情况下,它也会被Spring扫描到IoC容器里。
于是针对上面的配置可以采用注解@ComponentScan(basePackages = “com.awa.*”,excludeFilters = {@ComponentScan.Filter(classes = Service.class)}),
这样,使用@Service注解的类不会被装配到IoC容器里。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值