SpringBoot- 全注解下的 SpringIOC

本贴最后更新于 2327 天前,其中的信息可能已经渤澥桑田

SpringBoot - 全注解下的 SpringIOC

springboot 是基于 springframework 的全注解的 web 框架,它无需配置 xml,所以相比较于 spring+springmvc 它可以节省更多的开发周期

什么是 IOC(Inversion of Controller)?

IOC 即是控制反转,把创建对象的控制权交给第三方则叫反转。正转则是一般性的 j2ee new 对象式的开发,多个 Bean 的容器则叫做 IOC 容器。反转大大降低了代码的耦合性。

准备 - @Configuration @Bean 的简单使用

@Configuration public class Appconfig{ @Bean(name="user") public User initUser(){ User user = new User(); user.setId(1L); user.setUserName("user_name_1"); user.setNote("note_1"); return user; } }

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

@Bean 代表将 initUser 方法返回的 POJO 装配到 IOC 容器中,而其属性 name 定义这个 bean 的名称,如果没有配置它,则将方法名称"initUser"作为 Bean 的名称装配到 Spring IOC 容器中。

使用实例:

public class IOCTest{ private static Logger log = Logger.getLogger(IOCTest.class); public static void main(String[] args){ ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); User user = ctx.getBean(User.class); log.info(user.getId()); } }

起步 - 如何去装配 Bean

1.扫描装配 Bean

因为如果用 @Bean 去一个个装配的话会显得很繁琐,所以推荐使用扫描装配。

@Component:标明哪个类被扫描进入 Spring IOC 容器。
@ComponentScan:标明采用何种策略去扫描装配 Bean。

@Component("user") public class user{ @Value("1") private Long id; @Value("user_name_1") private String usename; @Value("note_1") private String note; /**setter and getter**/ }

@Component 表示这个类将会被 SpringIOC 容器扫描装配,其中配置的"user"则是作为 Bean 的名称。为了让 Spring IOC 容器装配这个类,需要改造类 APPConfig

@Configuration @ComponentScan public class Appconfig{ }

这里加入 @ComponentScan 意味着它会进行扫描,但是它只会扫描类 APPConfig 所在的当前包和其子包(还可以指定扫描包,看下)。所以也要把 User.java 移动一下位置。

测试

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); User user = ctx.getBean(User.class); log.info(user.getId());

@ComponentScan 扫描指定包:

@ComponentScan("com.springboot.demo.*")
@ComponentScan(basePackage={"com.springboot.demo.pojo"})
@ComponentScan(basePackageClasses = {User.class})

Q:当标注了 @Service 的类在被扫描的包当中,则如何使它不被扫描?
A:还是使用 @ComponentScan,不过另加一个参数即可:
@ComponentScan("com.springboot.demo.*",excludeFilters = {@Filter(classes = {Service.class})})

2.装配第三方 Bean

当我们需要引入第三包的时候,很可能 希望把第三方包的类对象也放入到 SpringIOC 的容器中,这是使用 @Bean 注解就 ok 了。
举栗(引入 DBCP 数据源):

<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
@Bean(name="dataSource") public DataSource getDataSource() { Properties props = new Properties(); props.setProperty("driver", "com.mysql.jdbc.Driver"); props.setProperty("url", "jdbc:mysql://localhost:3306/demo"); props.setProperty("username", "root"); props.setProperty("password", "123456"); DataSource dataSource = null; try { dataSource = BasicDataSourceFactory.createDataSource(props); } catch (Exception e) { e.printStackTrace(); } return dataSource; }

加深 - 依赖注入(Dependency Injection)

依赖注入就是将实例变量传入到一个对象中去。(Dependency injection means giving an object its instance variables)

  • 控制反转是一种思想
  • 依赖注入是一种设计模式

IoC 框架使用依赖注入作为实现控制反转的方式,但是控制反转还有其他的实现方式,例如说 ServiceLocator,所以不能将控制反转和依赖注入等同。

1. @Autowired

它是 Spring 中最常用的注解之一,十分重要,它会根据属性的类型(by type)找到对应对的 Bean 进行注入。
栗子:

//动物接口 public interface Animal { public void use(); }
//人类接口 public interface Person { //使用动物服务 public void service(); //设置动物 public void setAnimal(Animal animal); }
public class Dog implements Animal{ @Override public void use() { System.out.println("狗【"+Dog.class.getSimpleName()+"】是看门的"); } }
public class BussinessPerson implements Person { @Autowired private Animal animal = null; @Override public void service() { this.animal.use(); } @Override public void setAnimal(Animal animal) { this.animal = animal; } }

如上,spring 容器会通过注解 @Autowired 将 Dog 注入到 BussinessPerson 实例中

Q:但是,加入又有一个动物类 cat,那么它会选择哪个注入?怎么解决这个错误?
A: 因为 @Autowired 首先会根据类型找到对应的 Bean,如果类型不是唯一的,那么它会根据其属性名称和 Bean 的名称进行匹配。如果匹配得上,就用该 Bean,如果还是无法匹配就会抛出异常。

@Autowired private Animal dog = null;

因为将 animal 修改为了 dog,所以它会找到 dog 类

注:

  1. 因为 @Autowired 是一个默认必须要找到对应 Bean 的注解,所以如果不能确定其标注属性是否存在,或者允许这个被标注的属性为 null。则可以配置 @Autowired 属性 required 为 false。@Autowired(required =false)
  2. 它除了可以标注属性外还可以标注方法。甚至还可以使用在方法参数上
@Override @Autowired public void setAnimal(Animal animal) { this.animal = animal; }

它会使用 setAnimal 方法从 IOC 容器中找到对应的动物进行注入。

2. @Primary 和 @Quelifier

@Primary:它是一个修改优先权的注解,比如上面的例子,当我们有猫有狗时,假设这次使用猫,name 只需要在猫类的定义上加入 @Primary 就可以了

@Component @Primary public class Cat implements Animal{ ...... }

这里的 @Primary 的含义告诉 SpringIOC 容器,当发现有多个同类型的 Bean 时,请优先使用我进行注入.

Q: 如果 @Primary 作用在多个类上,其结果是 IOC 容器还是无法区分采用哪个 Bean 的实例进行注入,那么该采取什么样的情况呢?
A: 可以使用 @Quelifier 结合 @Autowired 一起使用,则可以通过类型和名称一起查找 Bean。

@Autowired @Quelifier("dog") private Animal animal = null;

通过上面的代码,即使 cat 已经标注了 @Primary,但是我们还是可以拿到 dog 提供服务。

3. 带参数的构造方法实现注入

public class BussinessPerson implements Person { private Animal animal = null; public BussinessPerson(@Autowired @Quelifier("dog") Animal animal){ this.animal = animal; } @Override public void service() { this.animal.use(); } @Override public void setAnimal(Animal animal) { this.animal = animal; } }

上面取消了对 animal 的 @Autowired 注解而是在构造参数中加入了 @Autowired@Quelifier 注解

  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3455 回帖 • 160 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    948 引用 • 1460 回帖 • 1 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    173 引用 • 517 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...