跟面试官刚聊几句,被发现连这几道都不会,便被请了出去

2023-03-07 09:51:14 浏览数 (1)

IoC会怎么面试

Spring面试中,我们会经常被问到一个问题,那就是 什么是IoC?,说实话,我一直认为这个问题很容易回答,但又很难答的好。因为每个使用过的人对IOC都会有不同的看法,你同样的回答可以让这个面试官满意,但不一定就能让另一个面试官满意。

简单回答

IoC是一种控制反转的思想,主要有依赖查找和依赖注入实现。他们之间的关系就类似于好莱坞原则“你不要给我打电话,我们需要的时候会给你打电话”,即低层只需要管理好自己的具体实现,而高层有自己的一套做事逻辑,需要你的时候会去找你,不需要的时候就不会去调用你。

进一步回答

但是进一步也可以这么细讲,按照IoC的定义,那么有很多方面都可以是IoC,我们经常用的JavaBeans就是Ioc的一个实现,在基于Spring框架的项目开发中,Bean的存在是极为重要的,也因此很多面试都会专门挑Bean的生命周期来问。Servlet也是IoC的一种实现,因为他可以去依赖或者反向地通过JNDI(Java Naming and Directory Interface)的形式得到一些外部的资源,比如DataSource或者EJB的组件。这些都是比较常见的IoC实现。

然后讲讲反转控制,这里简单举个例子,比如消息机制,它就是其中的一种,使用过消息事件的程序员都知道,相比我们传统的调用方式,消息机制是一种被动的、推送的方式。这其实也属于Ioc中的一种实现。

拓展回答

再往深处说,就涉及到另一个我司经常问的一个问题:依赖查找和依赖注入的区别?

一般我会这样回答,依赖查找是手动或者主动的依赖查找方式,一般通过名称、通过类型、通过路径的方式来查找。是需要依赖于容器标准的API来实现,比如Servlet的API,这是一种显现的调用API的方式去获取你想要的资源。Spring-beans的BeanFactory里的getBean方法。

而依赖注入则是手动或者自动的绑定的方式,它不需要依赖特定的容器和API。最为常见的一种使用就是@Autowired的使用了。

一般如果只是面试初级程序员,那么面试官问完依赖查找和依赖注入后一般都会停止,如果你工作过2-3年,那么当你回答的问题涉及到Bean时,面试官可能会往更深层去提问你,考察你关于源码的了解情况。因为Bean本身就是IoC的一种实现,很多面试官问完IoC就会让你讲讲Bean,小面曾经就遇过“你知道几种方法去注册一个Spring Bean?

一般回答 通过BeanDefinition和外部单体对象来注册 即可得分。

运气比较差的就会被接着细问接下来的实现。

没错!那个运气比较差的就是我!!

BeanDefinition方式做法有很多,比如

1、XML配置元信息<bean name="..." .../>

2、使用注解来配置元信息@Bean,@Component,@Import,以及使用Java API来配置元信息

看看下面怎么使用JAVA 注解和标准API来怎么注册Bean

JAVA 注解和BeanDefinition对象:

代码语言:javascript复制
//3.通过@Import方式注册
@Import(BeanRegistrationDemo.Config.class)
public class BeanRegistrationDemo {

    public static void main(String[] args)
    {
        //创建一个BeanFactory容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        //注册Configuration Class(配置类)
        applicationContext.register(BeanRegistrationDemo.class);
      
        applicationContext.refresh();
        
        User user = applicationContext.getBean("user", User.class);
        User user1 = applicationContext.getBean("user1", User.class);
        System.out.println("user对象是否一致:" (user==user1));


        //关闭Spring应用上下文
        applicationContext.close();
    }
    
 //2.通过@Component方式注册
    @Component
    public static class Config
    {
     
        //1.通过@Bean方式注册
        @Bean(name = {"user","user1"})
        public User user()
        {
            User user = new User();
            return user;
        }
    }

}

//通过BeanDefinition注册
public static void main(String[] args)
{
        //创建一个BeanFactory容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        
        //通过BeanDefinition注册API实现
        registerBeanDefinition(applicationContext,"user");
    
     //启动上下文
        applicationContext.refresh();

        User user = applicationContext.getBean("user", User.class);
        System.out.println("user对象:"   user);


        //关闭Spring应用上下文
        applicationContext.close();
}

public static void registerBeanDefinition(AnnotationConfigApplicationContext applicationContext,String beanName)
{
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("id", 1L);
        beanDefinitionBuilder.addPropertyValue("nickName", "xxxx");
     //注册bean
        applicationContext.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
}

@Bean,@Component,@Import都可以注册Bean,且一起用也不会出现Bean注册重复的问题。不过一般项目开发中,使用@Bean就足够了。

BeanDefinition则是把一个类手动的设置成一个Bean,不想注解那般方便,但是也是一种实现方式。

外部单体对象注册:

代码语言:javascript复制

    public static void main(String[] args)
    {
        //创建一个BeanFactory容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        
        //将当前类作为配置类(随便一个具体的实现类来替换即可)
        EchartServiceImpl echartServic = new EchartServiceImpl();
        
        //注册方法一
        //注册Configuration Class(配置类)
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        beanFactory.registerSingleton("echartService", echartServic);

        //注册方法二
        //注册Configuration Class(配置类) -> Spring Bean
        applicationContext.registerBean("echartService", EchartServicImpl.class, () -> echartServic);

        //注册方法一和方法二只能二选一,否则会报bean名称相同的异常
        //启动Spring应用上下文
        applicationContext.refresh();

        //获取bean方法一
        EchartServicImpl service1 = applicationContext.getBean("echartService",EchartServicImpl.class);
        System.out.println("是否相等:" (service1 == echartServic));

        //获取bean方法二
        EchartServicImpl servic2 = beanFactory.getBean("echartService", EchartServicImpl.class);
        System.out.println("是否相等:" (servic2 == echartServic));

        //关闭Spring应用上下文
        applicationContext.close();

    }

简单讲解一下外部单体对象

1.我们需要创建一个BeanFactory工厂,new AnnotationConfigApplicationContext(),用它来存放我们的业务bean,存放可以直接使用applicationContext对象的registerBean()方法,也可以使用applicationContext.getBeanFactory()皆可。

2.注册完bean后使用applicationContext.refresh()启动Spring上下文后就可以使用依赖查找去获取bean了,然后判断完是否是同一个bean后,调用close()方法关闭掉Spring上下文销毁bean。

3.一个简单的Bean注册与依赖查找就完成了。

结束

这次的介绍到此为止,IOC的运用实在多种多样,因为在Spring框架的开发中,与它有关的东西实在太多太多,接下来的内容,我会在后续文章中对IOC进行介绍。关注我,不要让自己错过任何一点知识点。

0 人点赞