Spring IOC&DI————(1)

发布于:2025-05-20 ⋅ 阅读:(16) ⋅ 点赞:(0)

1,IOC&DI讲解

1,Spring是啥

Spring就是一个开源框架,他们让我们开发变得更加简单,简单来说,Spring就是一个包含了众多工具方法的IOC容器。那么啥是容器呢,我们之前学习的集合,数据结构那块就是容器,用来存储数据容器,这里也是一样,比如Tomcat就是一个Web容器;

2,啥是IOC

那么什么是IOC呢,我们其实在此之前已经使用过了,大家有没有发现,之前在RequestMapping下的代码是一个对象吧,我们调用它里面的方法实现调用功能,但是有个问题啊,我们从来都没new过对象,是不是,从来都没有,但是我们还是可以调用,这个因为这个RequestController和Controller注解中有IOC注解,就是会把这个类交给Spring管理,交给Spring管理,Spring就会帮我们来实例化对象,就是完全交给Spring;IOC简单来说就是Spring提供的存功能;

IOC带来的好处:
1,资源集中管理:IOC容器会帮我们管理一些资源,比如对象,我们在使用的时候,直接过去取就完了;

2,降低代码耦合度,创建实例的时候不用去关心实例的细节;

3,啥是DI

DI的英文翻译为中文的意思就是依赖注入,这是啥意思呢,刚才说了IOC是存,那么DI就是取,

我们可以通过一些列注解来取到我们需要的Bean,Bean就是对象;

3,Spring,Spring MVC,Spring SpringBoot关系:

三者的关系呢:

1,Spring Boot是基于Spring,Spring Boot是基于Spring框架的封装,简化了配置和部署

2,Spring MVC属于Spring,Spring MVC是Spring的Web模块,Spring Boot默认集成MVC

3,Spring Boot整合Spring全家桶,Spring Boot 可以整合 Spring MVC、Spring Data、Spring Security 等模块。


2,IOC详解

IOC即控制反转,我们想掌握IOC就是掌握IOC容器的创建和Bean的存储;

Bean的存储提供了两类注解:
1,类注解

@Controller,@Service,@Repository,@Component,@Configuration

2,方法注解

@Bean

1,类注解

1,@Controller控制器存储
@Controller
public class UserController {
    public void sayHello(){
        System.out.println("Hello,Controller");
    }
}

使用注解就说明吧这个类给Spring管理了,

@SpringBootApplication
public class JavaTest2025519Application {

    public static void main(String[] args) {
        //或缺上下文对象
        ApplicationContext context = SpringApplication.run(JavaTest2025519Application.class, args);
        //从上下文中或缺对象
        UserController userController = context.getBean(UserController.class);
        //使用对象
        userController.sayHello();
    }

}

 我们可以直接获得到UserController、大家有没有唤醒一些记忆,这个.class怎么那么熟悉呢,这不反射的类加载嘛~,还有这个上下文,大家从哪听过呢,线程那,大家还有记忆没有,这里的上下文呢,指的是当前的运行环境,可以看做容器,容器存储了很多东西,就是运行环境,

我们看看有没有打印出来:

获取成功了,我们成功获取了一个对象,我们这个对象是根据类型创建的,这里我们还没指定Bean,如果有多个Bean呢,我们可能会在注入的时候进行操作,我们在获取这也能操作,我们还提供了其他的getbean方法,这个ApplicationContext继承了BeanFactory的功能,这里常用的三种方法:

1,getBean(类型)

2,getBean(Sting name)

3,getBean(String name,类型)

来试试:
 

        UserController userController = context.getBean(UserController.class);
        //使用对象
        userController.sayHello();

        UserController userController1 = (UserController) context.getBean("userController");
        userController1.sayHello();

        UserController userController2 = context.getBean("userController", UserController.class);
        userController2.sayHello();

三种方法,打印结果:

这里注意这个String就是以小驼峰命名的类名,如果前两个名字都是大写就不动,就一个大写就改成小驼峰的命名规则,我们还没说多个bean的情况呢,具体体现在哪呢,先提前剧透一下,

我们会使用getBean的(String,类型)来获取到类,String对应的就是bean起的名字,不懂没关系,一会儿会讲解bean;

@Controller
@Data
public class UserController2 {
    private String name;
    private Integer age;
    public void sayHello(){
        System.out.println("Hello,Controller2");
    }

    public void say(){
        System.out.println(name+age);
    }

    @Bean("hei1")
    public UserController2 hei1(){
        UserController2 userController2 = new UserController2();
        userController2.setAge(18);
        userController2.setName("zhangsan");
        return userController2;
    }

    @Bean("hei2")
    public UserController2 hei2(){
        UserController2 userController2 = new UserController2();
        userController2.setAge(19);
        userController2.setName("zhangsan");
        return userController2;
    }
}
        UserController2 userController3 = context.getBean("hei1", UserController2.class);
        userController3.say();

        UserController2 userController4 = context.getBean("hei2", UserController2.class);
        userController4.say();

看打印结果:

 

所以结论嗷,就是我们给Spring的类,Spring会把每个类都起一个名字,根据名称来获取对应的对象,所以是不能重名的;

我们会根据Spring中的bean来对应对象的,比如我们前三个都是UserController用的是一个类型创获取的三个对象,Spring内部创建的,所以地址应该是想同的,后面两个是UserController2中的两个bean,所以地址应该是不同的,我们来试试:
 

        System.out.println(userController);
        System.out.println(userController1);
        System.out.println(userController2);;
        System.out.println(userController3==userController4);

 

 ok,下面来个面试题,

ApplicationContext和BeanFactory

1,获取Bean是beanFactory提供的功能

2,BeanFactory提供了基础访问容器的功能,ApplicationContext是BeanFactory的子类,继承了BeanFactory之外还提供了国际化支持,资源访问支持,事件传播支持,

3,从性能方面,Application更高效,会一次加载并初始化所有的Bean,而BeanFactoty是需要哪个才加载哪个,更加轻量化,有点像单例模式的懒汉和饿汉模式;

2,@Service(服务存储)
@Service
public class UserService {
    public void sayHello(){
        System.out.println("Hello,I'm Service");
    }
}
        UserService userService = context.getBean(UserService.class);
        userService.sayHello();

 

3,@Repository(仓库存储)
@Repository
public class UserRepository {
    public void sayHello(){
        System.out.println("Hello,I'm Repository");
    }
}
        UserRepository userRepository = context.getBean(UserRepository.class);
        userRepository.sayHello();

 

4,@Component(组件存储)
@Component
public class UserComponent {
    public void sayHello(){
        System.out.println("Hello,I'm Component");
    }
}
        UserComponent userComponent = context.getBean(UserComponent.class);
        userComponent.sayHello();

 

5,@Configuration(配置存储)
@Configuration
public class UserConfiguration {
    public void sayHello(){
        System.out.println("Hello,I'm Configuration");
    }
}
        UserConfiguration userConfiguration = context.getBean(UserConfiguration.class);
        userConfiguration.sayHello();

 

2,为啥要这么多类注解

整这么多注解嘎哈呀,其实他们没有太大区别的,除了@Controller,@Controller可以返回视图大家还记得不,其他的就在语义上有区别,我们是可以进行替换的,但是还是推荐按标准来;这些注解都是@Component的子类;

@Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应

@Servie:业务逻辑层,处理具体的业务逻辑.

@Repository:数据访问层,也称为持久层.负责数据访问操作

@Configuration:配置层.处理项⽬中的⼀些配置信息.

3,方法注解

类注解是写在类上的,但是嗷,存在两个问题

1,使用外部包的类是没办法添加类注解的

2,一个类,有多个对象

1,定义一个对象
@Data
public class User {
    private String name;
    private Integer age;
}

先来一个User,

@Component
public class UserController3 {

    @Bean
    public User get(){
        User user = new User();
        user.setName("yaoyu");
        user.setAge(78);
        return user;
    }
}

新的控制器,我们想拿到这个User,直接获取想要的对象

        User user = context.getBean(User.class);
        System.out.println(user);

 

2,定义多个对象
@Component
public class UserController3 {

    @Bean
    public User get(){
        User user = new User();
        user.setName("yaoyu");
        user.setAge(78);
        return user;
    }

    @Bean
    public User get2(){
        User user = new User();
        user.setName("张三");
        user.setAge(18);
        return user;
    }
}

那么接下来如何应对呢,我们后面注入的时候有更好的方法,现在我们可以通过GetBean方法来输入方法名来区分比如get和get2,

        User user1 = context.getBean("get",User.class);
        System.out.println(user1);

        User user2 = context.getBean("get2",User.class);
        System.out.println(user2);

 

3,重命名Bean

我们还可以给Bean起名字:

    @Bean("h1")
    public User get3(){
        User user = new User();
        user.setName("yaoyu21212");
        user.setAge(78123123);
        return user;
    }

    @Bean("h2")
    public User get4(){
        User user = new User();
        user.setName("张三123");
        user.setAge(18123123);
        return user;

 

        User user3 = context.getBean("h1",User.class);
        System.out.println(user3);
        User user4 = context.getBean("get3",User.class);
        System.out.println(user4);

我们看看这个是我们起的名字生效呢,还方法名生效呢, 没有类名为get3,看来还是自定义的名的优先级比较高一点;

        User user3 = context.getBean("h1",User.class);
        System.out.println(user3);
        User user5 = context.getBean("h2",User.class);
        System.out.println(user5);

 

 这下Bean就讲解完了;

4,扫描路径

我们的默认扫描路径就是Application同级以及以下的路径为扫描路径,我们也是可以修改的,使用@ComponentScan({"com.example.demo"})注解,里面是修改的路径,这么说的话如果被那5个类注解修饰的Bean注解也是不一定完全生效的,这是因为可能没配置扫描路径,如果在扫描路径外,那就白忙活了;


3,DI详解


网站公告

今日签到

点亮在社区的每一天
去签到