spring源码解读(一)

spring源码解读(一)

1.1 从XML配置开始

我们在resources目录下创建beans.xml文件 用于注入bean

  1. 先创建实体类User
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private Long id;
    private String name;
}
  1. 在resources下创建beans.xml配置文件

beans.xml内容如下,使用bean标签注册一些组件<新建Person.java>:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="user" class="pers.amos.cap1.User">
        <property name="id" value="17"/>
        <property name="name" value="amos"/>
    </bean>

</beans>

测试类

public static void main(String[] args) {
        //创建容器 并且加载配置文件
        //把beans.xml加载到容器中
        ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
        //从容器中获取bean
        User user = (User) app.getBean("user");
        System.out.println(user);
    }

打印结果:

User(id=17, name=amos)

1.2 使用注解完成注入

  1. 配置类- -相当于xml配置文件
@Configuration
public class Cap1MainConfig {
    //给容器中注册一个bean类型为返回值的类型
    //指定bean的名称为amos 相当于配置文件中的id
    //如果未指定名称 则使用默认名称:方法名
    @Bean("amos")
    public User getUser(){
        return new User(10010L, "amos");
    }
}

测试类


public class Test2 {

    public static void main(String[] args) {
        //创建容器
        //把配置信息加载到容器中
        ApplicationContext app = new AnnotationConfigApplicationContext(Cap1MainConfig.class);
        //从容器中获取bean
        User user = (User) app.getBean("amos");
        System.out.println(user);
	//根据类型获取bean的名称
        String[] beanNames = app.getBeanNamesForType(User.class);
        for (String name : beanNames){
            System.out.println(name);
        }
    }
}

2.componentScan扫描规则

image.png

创建OrderController、OrderService、OrderMapper并且分别添加@Controller、@Service、@Repository注解

1.创建配置类

@ComponentScan(value="pers.amos.cap2")表示扫描此目录下的包

@Configuration
@ComponentScan(value = "pers.amos.cap2", includeFilters = {
        //1.根据注解扫描 扫描pers.amos.cap2包下的Controller、Repository两个注解
        //@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Repository.class})
        //2.可分配类型 扫描指定的类
        //@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OrderController.class)
        //3.自定义过滤规则
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = AmosFilterType.class)
},      //使用默认扫描过滤器 includeFilters需要设置为false excludeFilters不需要设置
        useDefaultFilters = false)
public class Cap2MainConfig {

    @Bean
    public User user(){
        return new User(2L, "cap2 config");
    }
}

@ComponentScan value:指定要扫描的包 excludeFilters = Filter[] 指定扫描的时候按照什么规则排除那些组件 includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件 useDefaultFilters = false 默认是true,扫描所有组件,要改成false 扫描规则如下:

  • FilterType.ANNOTATION:按照注解
  • FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按BookService类型
  • FilterType.ASPECTJ:使用ASPECTJ表达式
  • FilterType.REGEX:使用正则指定
  • FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口

以自定义扫描规则为例:

//自定义扫描组件的过滤规则
public class AmosFilterType implements TypeFilter {

    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {

        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描类的信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();
        //获取类名
        String className = classMetadata.getClassName();
        System.out.println("----->"+className);
        //如果类名包含er则符合过滤规则
        if (className.contains("service")){
            return true;
        }
        return false;
    }
}

测试类


public class TestMain {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
        //从容器中获取定义的名称
        String[] beanNames = app.getBeanDefinitionNames();
        for (String name : beanNames){
            System.out.println(name);
        }
    }
}

以扫描指定注解为例

这里扫描的是@Controller和@Repository注解 useDefaultFilters 属性表示是否使用默认的过滤规则。 默认的过滤规则是扫描所有带有@Component注解的类。也就是说会扫描所有使用@Controller@Service@Repository注解的类。这样会使自定义的规则失效。 所以当设置扫描方式为注解扫描的时候,useDefaultFilters 一定要设置为false

配置类:

@Configuration
@ComponentScan(value = "pers.amos.cap2", includeFilters = {
        //1.根据注解扫描 扫描pers.amos.cap2包下的Controller、Repository两个注解
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Repository.class})
},  useDefaultFilters = false)
public class Cap2MainConfig {

    @Bean
    public User user(){
        return new User(2L, "cap2 config");
    }
}

扫描结果

cap2MainConfig
orderController
orderMapper
user

如果注解扫描时设置useDefaultFilters = true 扫描结果为:

cap2MainConfig
orderController
orderMapper
orderService
user

3.scope扫描规则

  • prototype: 多实例:IOC容器启动并不会去调用方法创建对象放在容器中,而是每次获取的时候才会调用方法创建对象
  • singleton: 单实例(默认):IOC容器启动会调用方法创建对象放到IOC容器中,以后每交获取就是直接从容器(理解成从map.get对象)中拿
  • request: 主要针对WEB应用,同一次请求创建一个实例
  • session: 同一个session创建一个实例

spring默认为单例模式

配置类

通过@Scope注解来设置Bean的模式

@Configuration
public class Cap3MainConfig {

    //向容器中创建对象
    @Bean
    @Scope("singleton")
    public User user(){
        System.out.println("创建对象user......");
        return new User(2L, "cap2 config");
    }
}

测试类

测试当前容器中的Bean:User是单例还是多例。如果是单例每次从容器中取出的对象应该是同一个 即user1 == user2,如果是多例那么user1 != user2

public class Cap3Test {

    public static void main(String[] args) {
        //创建容器
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
        System.out.println("创建容器完成.....");
        Object user1 = app.getBean("user");
        Object user2 = app.getBean("user");
        System.out.println(user1 == user2);

    }
}

返回结果

true

同样的道理可以将@Scope的值改变为prototype测试 容器中对象是否为多例模式

4.lazy懒加载

配置类

@Configuration
public class Cap4MainConfig {
	//给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
	/*
	 * 懒加载: 主要针对单实例bean:默认在容器启动的时候创建对象
	 * 懒加载:容器启动时候不创建对象, 仅当第一次使用(获取)bean的时候才创建被初始化
	
	 */

	//启用懒加载
	@Lazy
	@Bean
	public Person person(){
		System.out.println("给容器中添加person.......");
		return new Person("james",20);
	}
}
public class Cap4Test {

    public static void main(String[] args) {
        //创建容器
        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
        System.out.println("创建容器完成.....");
        Object user1 = app.getBean("user");
        Object user2 = app.getBean("user");
        System.out.println(user1 == user2);

    }
}

结果

创建容器完成.....
给容器中添加person.......

结果说明在懒加载机制下,对象在调用它的时候才会创建而不是在容器启动时就创建。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×