spring ioc其实就是控制翻转,帮你创建对象,不用在自己创建。在需要聚合引入时也会处理对象之间的关系。
ioc其实就是分两步:
第一步:将自己的对象写好后加上能被spring扫描的注解,通常的注解有:@Configuration,@Component,@Service,@Controller等等,看似好多被扫描标识的注解,其实具有被扫描功能的只有@Component,其他注解内部只是包含@Component所有才有了被扫描的功能,因为不会有人喜欢写重复冗余的代码,尤其是工具,所以spring也不会例外。
第二步:扫描的注解是:@ComponentScan,通过指定或默认扫描的范围去扫描标识过的对象,然后创建并加载到ico容器中,可通过ico容器的getBean方法将指定的对象取出使用。
1.ioc容器:org.springframework.context.ApplicationContext,这只是个接口,下面有很多的实现类,也就是说有很多的ico实现容器。我们这里使用的是其中一个叫import org.springframework.context.annotation.AnnotationConfigApplicationContext;的容器做demo演示。
2.扫描注解:@ComponentScan(basePackages = {"com.mr.li.*" }/* , excludeFilters = {@Filter(classes = {Person.class, Animal.class})} */) :扫描注解见名知意就是用来扫描需要加载到ico容器中的java类的。可以指明扫描范围,例如填写包名,也可过滤哪些不被扫描 excludeFilters中的内容就是不被扫描的。扫描的注解也较多如:@ComponentScans,@EntityScan,@EnableAsync
上代码:
1:先指定扫描哪些包,包括在里面也创建一些被ioc加载的bean
package com.mr.li.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import com.mr.li.entity.User; @Configuration @ComponentScan(basePackages = { "com.mr.li.*" }/* , excludeFilters = {@Filter(classes = {Person.class, Animal.class})} */) public class AppConfig { @Bean(value = "user1") public User getUser() { User user = new User(); user.setId(1000); user.setName("旺达"); return user; } @Bean(value = "user2") public User getUser2() { User user = new User(); user.setId(1001); user.setName("天天"); return user; } }
2.创建一些服务接口
package com.mr.li.service; public interface Person { void behavior(); }
package com.mr.li.service; public interface Animal { void behavior(); }
3,给这些接口一些实现类
package com.mr.li.service.impl; import org.springframework.stereotype.Component; import com.mr.li.service.Animal; @Component public class Cat implements Animal { @Override public void behavior() { System.out.println("喵喵喵~~~~~~~~~"); } }
package com.mr.li.service.impl; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import com.mr.li.service.Animal; @Primary @Component public class Dog implements Animal { @Override public void behavior() { System.out.println("汪汪汪~~~~~~~~~~"); } }
package com.mr.li.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import com.mr.li.service.Animal; import com.mr.li.service.Person; @Component public class Man implements Person { @Qualifier("cat") @Autowired private Animal animal; @Override public void behavior() { animal.behavior(); } }
4.user演示类
package com.mr.li.entity; import lombok.Data; @Data //@Component public class User { // @Value(value = "100") //这种直接赋值的优先级最高 private long id; // @Value(value = "章大狗") private String name; @Override public String toString() { return "id:"+ id + "name:" + name; } }
5.测试
package com.mr.li.test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.mr.li.config.AppConfig; import com.mr.li.entity.User; import com.mr.li.service.Person; import com.mr.li.service.impl.Man; import lombok.extern.slf4j.Slf4j; @Slf4j public class Test { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); Person person = ctx.getBean(Man.class); person.behavior(); // User user = ctx.getBean(User.class); User user = ctx.getBean("user2", User.class); log.info("user:{}", user); } }
以上代码的行为:
AppConfg:扫描了定义的包,然后在身演示创建一些bean,可以看到同样类型的bean给了不同的名称,这些类对象在扫描后会被加载到ico容器中去,其中在ico中存储的名称就是指定的名称,如果没指定则使用方法名首字母小写作为名称。
Man:人物类,他实现了Person接口,然后自身加了@Component被扫描注解,我们会发现它里面有引入Animal类的,加了@Autowired注解,此注解就是通过ioc引入Animal的实现类对象,但他有2个实现类对象,所以需要指定到底使用哪个实现类作为对象引入。三种方式:
第一种:直接将变量名animal改为他的子类的类名即可,这个类名是ioc中的变量名,默认会将类首字母小写,也可指定。
第二种:在需要引入的实现类上加@Primary注解,此注解意思是如果没有特殊情况就加载他,但在两个实现类上都加也不行,他的优先级小于@Qualifier注解。
第三种:@Qualifier注解,加载引入的类上同@Autowired一起存在,同样需要指定ioc中存储对应的变量名。
Test:演示了,创建一个ioc容器,加载是他内部的事,注意传入加载的第一类即可。然后演示从ioc中取出对象并使用。