Spring面试题

Spring IOC

传统new对象产生耦合问题如何改进?
xml+工厂类(解析xml、反射生成实例)生产实例,这样就不会耦合了
Spring IOC大致就是这个原理

Spring Bean作用范围

单例模式下,对象跟容器生命周期一致,容器创建时对象就创建,容器销毁时对象销毁

原型模式下,只有当我们管容器要对象的时候,容器才创建对象,而且只有对象长时间不用时,才会被垃圾回收

延迟加载

什么是延迟加载

第一次向容器getBean的时候才去创建和实例化对象

为什么要有延迟加载

1、开启延迟加载一定程度提高容器启动和运转性能

2、不常用的Bean开启延迟加载,这样偶尔使用再加载,不必从一开始就占用资源

延迟加载原理

延迟加载原理就是实例化过程中,判断是否延迟加载标志,是的话就不实例化

1 、 普通bean初始化是容器启动初始化阶段执行
2、 lazy-init=true修饰的bean 是容器第一次进行context.getBean()时才触发的
3、 Spring启动的时候会把所有bean信息解析成BeanDefinition,并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个BeanDefinition 进⾏处理,如果是懒加载,则容器初始化阶段不处理
4、 其他bean在容器初始化阶段初始化并依赖注入
5、 立即加载的bean1引用了延迟加载的bean2,那么bean1初始化时,也会去实例化bean2

Spring动态代理

当被代理对象没有实现任何接口时,Spring 选择Cglib
当被代理对象实现了接口,Spring 选择JDK

SpringBean生命周期

听说大厂爱问这个问题。

1、调用Bean构造方法或者工厂方法实例化Bean

2、依赖注入完成属性值的注入

3、若有BeanPostProcessor,则调用该接口的预初始化方法(postProcessBeforeInitialization)

4、若Bean实现类InitializingBean,调用afterPropertiesSet方法

5、若有BeanPostProcessor,则调用该接口的初始化方法(postProcessAfterInitialization)

此时,bean就能用了

容器销毁时,若Bean实现了DisposableBean接口,则调用destroy方法

在这里插入图片描述

Spring AOP原理

1、AOP原理就是动态代理

2、容器初始化过程中⽬标Bean已经完成了代理,并返回了代理对象

2、默认情况下,Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还是CGLIB。当被代理对象没有实现任何接⼝时,Spring会选择CGLIB。当被代理对象实现了接⼝,Spring会选择JDK官⽅的代理技术,不过我们可以通过配置的⽅式,让Spring强制使⽤CGLIB。
设置proxyTargetClass=true强制使⽤Cglib 代理,什么参数都不设并且对象类实现了接⼝则默认⽤JDK 代理,如果没有实现接⼝则也必须⽤Cglib

3、在后置处理器的postProcessAfterInitialization方法里面,就进行代理对象的创建

FactoryBean和BeanFactory

如果Bean的创建过程涉及复杂的逻辑,不是注解和xml文件就能解决的,就得借助FactoryBean,这是一个接口

//配置文件这么写:
//虽然这里指定的是MyFacotryBean,但是得到的bean却是Account
<bean id="myAccount" class="com.lagou.edu.dao.factory.MyFacotryBean"/>


// 代码这么写:
//实现FactoryBean接口即可
public class MyFacotryBean implements FactoryBean<Account> {

    @Override
    public Account getObject() throws Exception {
        Account account=new Account();
        account.setName("BBBB");
        return account;
    }

    @Override
    public Class<?> getObjectType() {
        return Account.class;
    }
}

Spring事务注解@Transactional

@Transactional如果加在接口上,会影响他的所有实现类

原理

AOP(动态代理)将事务控制逻辑织入到业务代码中
在这里插入图片描述

事务传播机制

事务往往在service层控制,如果service 层A方法调用了另一个service层的B方法,且A B方法本身已被添加了事务控制,那么A调用B时,就需要事务的一些协商,叫做事务的传播行为。记住这两个常见的应该就可以了:
propagation_required:当前没有事务,就新建一个事务执行;当前有事务,就加入到这个事务(默认)
propagation_supports:当前没有事务,就以非事务执行;当前有事务,就加入到这个事务

BeanFactory和ApplicationContext区别

BeanFactory是顶层接口,ApplicationContext是他的子接口
ApplicationContext比BeanFactory拥有更多的功能,比如国际化支持和资源访问(xml、java配置类)等
1、ApplicationContext支持国际化:因为扩展了MessageResource接口
2、BeanFactory在初始化容器时,并未实例化Bean,直到第一次访问某个Bean 时才实例目标Bean;而ApplicationContext 则在初始化应用上下文时就实例化所有单实例的Bean
3、ApplicationContext 的主要实现类是ClassPathXmlApplicationContext 和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件

其实我很好奇这为什么是一道面试题,问这个干嘛?大佬们请在评论区帮我解答

启动IOC容器的方式

1、java环境下启动:

ClassPathXmlApplicationContext:从类的根路径下加载配置⽂件(推荐使⽤)
FileSystemXmlApplicationContext:从磁盘路径上加载配置⽂件
AnnotationConfigApplicationContext:纯注解模式下启动Spring容器

2、web环境下启动:在web.xml里面配置启动方式,使用监听器来启动

<web-app>
	<display-name>Archetype Created Web Application</display-name>
    <!--配置Spring ioc容器的配置⽂件-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <!--使⽤监听器启动Spring的IOC容器-->
    <listener>
        <listener-
        class>org.springframework.web.context.ContextLoaderListener</listener-
        class>
    </listener>
</web-app>

实例化Bean的方式

1、使用无参构造(反射)

<bean id="userService" class="com.lagou.service.impl.TransferServiceImpl"></bean>

2、使用静态方法创建(工厂模式)—工厂类+产生bean的静态方法

<bean id="userService" class="com.lagou.factory.BeanFactory"  factory-method="getTransferService"></bean>

3、实例化方法创建—工厂类+产生bean的成员方法(所以此时工厂bean需要实例化)

<bean id="beanFactory"  class="com.lagou.factory.instancemethod.BeanFactory"></bean>
<bean id="transferService" factory-bean="beanFactory" factory-method="getTransferService"></bean>

依赖注入常见的注解

@Autowired:Spring提供的注解,默认按类型注入,需要指定名称时要加上@Qualifier注解

@Resource:J2EE提供的注解,默认按名称注入,也可同时指定按类型注入:@Resource(name=“manDao”,type=“ManDao”)

条件化Bean

1、@Conditional+@Bean:(就是说满足哪些条件下才去实例化这个bean)

下面这段代码意思就是只有环境变量中配置了magic变量,才会生产MagicBean

@Bean
@Conditional(MagicEnvCondition.class)  
public MagicBean magicBean(){
    System.out.println("magicBean...");
    return new MagicBean();
}

public class MagicEnvCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        return environment.containsProperty("magic");
    }
}

2、@Profile:该注解封装了 @Conditional注解,且ProfileCondition实现了Condition接口,此时只要在配置文件中配置spring.profiles.active=magic1,便会产生该bean(就是根据profile的激活状态来创建bean)

//使用方法:
@Bean
@Profile("magic1")
public MagicBean1 magicBean1(){
    System.out.println("magicBean1....");
    return new MagicBean1();
}


//@Profile注解:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {

	String[] value();

}


//ProfileCondition源码
class ProfileCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
		if (attrs != null) {
			for (Object value : attrs.get("value")) {
				if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
					return true;
				}
			}
			return false;
		}
		return true;
	}

}

控制bean的实例化顺序

某小厂面试问到了,当时只答了一个@ConditionalOnBean,面试官说这个算也不算。

因为这个注解的意思其实是说,当存在某个bean的时候才去实例化这个bean,如果不存在就不实例化了。

他的意思应该是这个:@DependsOn注解

还有一个注解@Order,这个数值越小,优先级越高

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值