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,这个数值越小,优先级越高