全注解下的Spring IOC

  • IoC是种通过描述来生成或者获取对象的技术,而这个技术不是Spring甚至不是java独有的。对于Java初学者更多的时候所熟悉的是使用new关键字来创建对象,而在Spring中则不是,它是通过描述来创建对象。因为Spring Boot并不建议使用XML,而是通过注解的描述生成对象,所以本文主要是通过注解来介绍Spring IoC技术。
  • 一个 系统可以生成各种对象, 并且这些对象都需要进行管理。还值得一提的是,对象之间并不是孤立的,它们之间还可能存在依赖的关系。例如,一 个班级是由多个老师和同学组成的,那么班级就依赖于多个老师和同学了为此Spring还提供了依赖注入的功能,使得我们能够通过描述来管理各个对象之间的关系。
    为了描述上述的班级、同学和老师这3个对象关系,我们需要个容器, 在spring中把每个需要管理的对象称为sping Bean (简称Bean)而spring管理这些Bean的容器,被我们称为Spring IoC容器(或者简称loC容器). IoC容器需要具备两个基本的功能:
  • 通过描述管理Bean, 包括发布和获取Bean;,
  • 通过描述完成Bean之间的依赖关系。

一,创建Bean的两种方法

1,使用@Bean注解来创建Bean

在Spring Boot中我们主要是通过注解装配Bean到Spring IOC容器中,为了贴近Spring Boot的需要,我们不在介绍与XML相关的IOC容器,而主要介绍一个基于注解的IOC容器,他就是AnnotationConfigApplicationContext,从名称就可以看出他是一个基于注解的IOC容器。

第一步:创建一个java类(POJO)文件:User.java

package com.atstudying.demo;

public class User {

    private int number;
    private String name;
    private String place;

/**
setterAndgetterWay
*/

第二步:在定义一个Java配置文件 文件:UserConfiguration.java

package configuration;
import com.atstudying.demo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration//代表这是一个java配置文件,Spring容器会根据它来生成IOC容器去装配Bean
public class UserConfiguration {

    @Bean(name="user")//代表initUser方法返回的POJO装配到ioc容器中,而其属性name定义这个bean名称,如果没有配置它,则将方法名称“initUser”作为Bean的名称保存到SpringIOC容器中
    public User initUser(){

        User user=new User();
        user.setName("zlj");
        user.setNumber(1);
        user.setPlace("beijing");
        return user;

    }

}

@Configuration//代表这是一个java配置文件,Spring容器会根据它来生成IOC容器去装配Bean
@Bean(name=“user”)//代表initUser方法返回的POJO装配到ioc容器中,而其属性name定义这个bean名称,如果没有配置它,则将方法名称“initUser”作为Bean的名称保存到SpringIOC容器中

第三步:使用AnnotationConfigApplicationContext来构建自己的IOC容器

package com.atstudying.demo;
import configuration.UserConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.logging.Logger;

@SpringBootApplication
public class IOCTest {

	private static Logger logger=Logger.getLogger(String.valueOf(IOCTest.class));
	public static void main(String[] args) {

		AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext(UserConfiguration.class);
		User user=annotationConfigApplicationContext.getBean(User.class);

		logger.info("姓名:"+user.getName());

	}

}

代码中将java配置文件UserConfiguration.java传递给AnnotationConfigApplicationContext的构造方法,这样他就可以读取配置。然后将配置里面的Bean装配到IOC容器,于是可以使用getBean方法获取对应的POJO,运行后可以看到如下日志
在这里插入图片描述

2,通过扫描装配Bean

  • 在Spring中允许我们通过XML或者Java配置文件装配Bean,但是由于Spring Boot是基于注解的方式,因此下面主要基于注解的方式来介绍Spring的用法,以满足Spring Boot开发者的需要。
  • 如果一个个的Bean使用注解@Bean注入Spring IoC 容器中,那将是一件很麻烦的事情。好在Spring还允许我们进行扫描装配Bean到IoC容器中对于扫描装配而言使用的注解是@Component和@ComponentScan. @Component是标明哪个类被扫描进入Spring loC容器,而**@ComponentScaon**则是标明采用何种策略去描装配Bean。

第一步:在com.configuration内创建文件:User_Component.java

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

@Component("UserConfiguration")
public class User_Component {

    @Value("2")
        private int number;
    @Value("lqx")
        private String name;
    @Value("hubei")
        private String place;
/**
setter和getter方法
/
}

这里的注解 @Component :表明这个类将被Spring IoC容器扫描装配,其中配置的"UserConfiguration”则是作为Bean的名称,当然你也可以不配置这个字符串,那么IoC容器就会把类名第一个字母作为小写,其他不变作为Bean名称放入到IoC容器中; 注解 @Value则是指定具体的值,使得Spring IoC给予对应的属性注入对应的值。

第二步:为了让Spring IoC容器装配这个类,需要改造类UserConfiguration.java

package configuration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class UserConfiguration_Component {
}

这里加入了 @ComponentScan,意味着它会进行扫描,但是他只会扫描类UserConfiguration所在的当前包和其子包。之前在com.configuration内创建文件:User_Component.java
就是这个原因。

第三步:测试

package com.atstudying.demo;

		import configuration.UserConfiguration_Component;
		import configuration.User_Component;
		import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.logging.Logger;

@SpringBootApplication
public class IOCTest {

	private static Logger logger=Logger.getLogger(String.valueOf(IOCTest.class));
	public static void main(String[] args) {

		AnnotationConfigApplicationContext annotationConfigApplicationContext=new AnnotationConfigApplicationContext(UserConfiguration_Component.class);
		User_Component user=annotationConfigApplicationContext.getBean(User_Component.class);

		logger.info("姓名:"+user.getName());

	}

}

代码中将java配置文件UserConfiguration_Component.java传递给AnnotationConfigApplicationContext的构造方法,这样他就可以读取配置。然后将配置里面的Bean装配到IOC容器,于是可以使用getBean方法获取对应的POJO,运行后可以看到如下日志
在这里插入图片描述
问题1:
为了使得User_Component类可以被扫描到,我们把它迁移到了不该放置他的配置包configuration,这样不太合理。为了更加合理,@ComponentScan还允许我们自定义扫描的包

  • 可以通过配置项basePackages定义扫描的包名,在没有定义的情况下,它只会扫描当前包和其子包下的路径;还可以通过配置项basePackageClasses 定义扫描的类;。其中还有includeFilters 和excludeFilters, includeFilters 是定义满足过滤器(Filter) 条件的Bean才去扫描,excludeFilters 则是排除过滤器条件的Bean,它们都需要通过一个注解@Filter去定义,它有一个 type类型,这里可以定义为注解或者正则式等类型。classes定义注解类,pattern 定义正则式类。

此时我们再把User_Component类放到包POJO中,这样User_Component类和UserConfiguration_Component类就不再同包,那么我们把AppConfg中的注解修改为:

@ComponentScan ("POJO.*")@ComponentScan (basePackages=
{"POJO"})@ComponentScan (basePackageClasses=
{"User_Component.class"})

不管采用上述何种方式,都可以让ioc容器去扫描User_Component类。
问题2:
当是有时候我们的需求是想扫描一些包,将一些Bean配置到Spring IOC容器中,而不是想加载这个包里面的Bean。比如我们有一个UserService类,为了标注她为服务类,将类标注@Service(该标准注入@Component,所以在默认情况下它会被Spring扫描装配到IOC容器中)为了不被装配,需要把扫描的策略改为

@Configuration
@ComponentScan(basePackages = "com.atstudying.demo.*",excludeFilters = {@ComponentScan.Filter(classes = {UserService.class})})

由于加入了excludeFilters 的配置,让标注了@Service的类不可以被IOC容器扫描注入,这样就把UserService类排除到SpringIOC容器中了
UserService.java

package com.atstudying.demo.UserService;
import org.springframework.stereotype.Service;
import configuration.User_Component;

@Service
class UserService {

    public void printUser(User_Component user){

        System.out.print("姓名:"+user.getName());
        System.out.print("学号:"+user.getNumber());
        System.out.print("位置:"+user.getPlace());

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值