1.什么是BeanDefinition?
- BeanDefinition表示Bean的定义。
- BeanDefinition有很多属性来描述Bean。
- Spring是根据BeanDefinition来创建Bean对象的。
- BeanDefinition是Spring非常核心的概念。
- @Compont、@Bean、@Service、<bean/>都会被解析为BeanDefnition对象。
- BeanDefinition创建bean:
-
public class SpringHello { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); //获取beanDedinition对象 AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition(); beanDefinition.setBeanClass(Demo.class); //设置bean的类型 applicationContext.registerBeanDefinition("demo",beanDefinition); //将beanDefinition注册到Spring容器中 applicationContext.refresh(); //刷新容器 Demo demo = (Demo) applicationContext.getBean("demo"); System.out.println(demo); } }
-
2.BeanDefinition中的属性。
- beanClass:表示bean类型,例如User.class。Spring在创建bean的过程中会根据此属性来实例化得到对象。
- scope:表示bean的作用域。
- sigleton表示单例的。
- prototype表示原型bean(多例)。
- isLazy:表示这个bean是否需要懒加载。原型bean的isLazy属性不起作用。
- 懒加载的bean,只会在第一次被使用的时候被创建。
- 非懒加载bean会在Spring启动过程中就会被创建好。
- dependsOn:表示bean所依赖的其它bean,在它被创建之前,它所依赖的其它bean得先被创建好。
- primary;表示bean是否为主bean。在Spring中同一个类型可以拥有多个bean对象。Spring在进行依赖注入时,根据类型进行查找会得到多个bean,此时Spring就会判断这些bean中是否存在一个主bean,如果存在则直接将主bean注入给对象。
- initMethodName:表示bean的初始化方法。Spring在创建bean的过程中有一个步骤叫做初始化,会在此步骤中调用此方法用来初始化bean。初始化方法的逻辑有程序员自己控制,表示我们可以自定义对bean进行加工。
3.什么是BeanFactory?
- BeanFactory是一种Spring容器。用来存储BeanDefinition对象
- BeanFactory就是Bean的工厂。
- BeanFactory用来创建bean、获取bean,是Spring中非常核心的组件。
4.BeanDefinition、BeanFactory、Bean对象的关系。
- BeanFactory根据BeanDefinition来创建Bean对象。
- BeanDefinition相当于是Bean工厂(BeanFactory)来生产Bean对象的原材料。
- Bean对象相当于是Bean工厂(BeanFactory)使用原材料(BeanDefinition)生产的产品。
5.BeanFactory的核心子接口和实现类
- ListableBeanFactory:
- ConfigurableBeanFactory:
- AutowireCapableBeanFactory:
- AbstrastBeanFactory:
- DefaultListableBeanFactory:最重要。支持单例bean、支持bean别名、支持父子BenaFactory、支持bean类型转化、支持bean后置处理、支持FactoryBean、支持自动装配等。
6.什么是Bean的生命周期?
- Bean的生命周期表示bean在Spring中从创建到被销毁的过程。
- 我们可以利用Bean的生命周期对bean的进行自定义加工。
- 核心步骤:
- Bean定义:将被@Service、@Compont、@Controller、@Bean标准的类或<bean/>定义的类解析,生成相应的BeanDefinition对象。
- 构造方法推断:一个类中有多个构造方法,此时就需要Spring来判断使用哪个构造方法来实例化bean。
- 实例化:使用构造方法推断得到的够造方法来创建一个普通对象。
- 属性填充:“实例化”得到的对象是不完整的对象,即未对该对象中的某些属性进行属性填充。“属性填充”也就是我们常说的自动注入、依赖注入。
- 初始化:在对对象进行属性填充之后,Spring提供了初始化机制,我们可以利用初始化机制对bean进行自定义加工。例如:可以将类实现initializingBean接口,实现afterPropertiesSet()方法对bean中的某些属性赋值或进行校验。
- 初始化后:是Spring创建bean过程中的最后一个步骤。我们常说的AOP就是在这个步骤中通过BeanPostProcessor机制来实现的,经过此步骤后的到的bean才是真正被Spring管理的bean对象。
7.@Autowirted注解。
- @Autowirted可以标在属性或方法上。
- 标在属性上:表示该属性需要进行依赖注入。Spring在进行bean的创建的过程中会在属性填充这一步,会基于实例化出来的对象,对该对象中标有@Autowired注解的属性自动进行属性赋值。Spring会根据该属性的类型去Spring容器中查找,如果查出多个,再根据属性名称进行确定一个。如果requited属性为true,并且根据属性信息找不到属性对象则抛出异常。
@Component public class Demo { @Autowired private SpringHello springHello; public Demo(){ } public Demo(SpringHello springHello) { this.springHello = springHello; } public SpringHello getSpringHello() { return springHello; } public void setSpringHello(SpringHello springHello) { this.springHello = springHello; } }
- 标在方法上:
@Autowired public void sayHello(SpringHello springHello){ System.out.println("Hello"+springHello.toString()); }
- 普通方法:Spring在bean的创建过程中的属性填充阶段根据参数的类型和参数的名称在Spring容器中查找相应对象当做方法入参,自动反射调用该方法。
- 构造方法上:Spring在bean的创建过程中的构造方法推断的过程中使用该构造方法实例化对象,在反射调用构造方法之前,会根据参数的类型和参数名去Spring容器中查找对象当做构造方法的入参。
@Autowired public Demo(SpringHello springHello) { this.springHello = springHello; }
- 标在属性上:表示该属性需要进行依赖注入。Spring在进行bean的创建的过程中会在属性填充这一步,会基于实例化出来的对象,对该对象中标有@Autowired注解的属性自动进行属性赋值。Spring会根据该属性的类型去Spring容器中查找,如果查出多个,再根据属性名称进行确定一个。如果requited属性为true,并且根据属性信息找不到属性对象则抛出异常。
- @Autowirted注解中的required属性值默认为true。表示如果没有对象可以注入则抛出异常。
8.@Resource注解。
- @Resource注解和@Autowired注解的作用类似。
- @Resource是Javat提供的;@Autowired注解是Spring提供的。
- @Resource和@Autowired自动注入的底层实现原理不同。
- @Resource注解有一个name属性,根据name属性是否有值,自动注入的实现流程是不同的。
- name属性有值:Spring会根据name属性的值去Spring容器中进行查找bean对象,找到就自动注入,未找到就报错。
- name属性无值:Spring先根据属性名在Spring容器中进行查找bean对象,若找到在自动注入该对象。若未找到则属性类型到Spring容器中进行查找bean对象,找到一个则进行注入。
9.@Value注解
- @Value和@Autowired、@Resource的作用类型,也是用来属性注入的。
- @Value注解是用来从Properties文件中来获取值得,并且@Value可以解析SpEL(Spring表达式)。
- @Value("wangLiJun"):将会把“wangLiJun”直接赋值给对应属性,如果属性不是String类型的并且不能进行转换,则报错。
- @Value("${wangLiJun}"):将会把${}中的值当成key从properties文件中查找相应的值并赋值给属性。如果没有找到,则会把"${wangLiJun}"当成普通字符串赋值给属性。
- @Value("#{wangLiJun}"):会将#{}中的字符串当做Spring表达式进行解析,Spring会把#{}中的内容当成bean在Spring容器中进行查找,如果找到则进行属性注入,如果没有找到则报错。
10.FactoryBean是什么?
- FactoryBean是Spring提供的一种较灵活的创建bean对象的方式。可以通过实现FactoryBean接口中的getObject()方法来返回一个对象,这个对象就是最终的bean对象。
- FactoryBean接口中的方法:
- Object getObject():返回的是bean对象。
- boolean isSingleton():返回的是否是单例bean对象。
- Class getObjectType():返回bean对象类型。
@Component("demo") public class Demo implements FactoryBean { @Override public Object getObject() throws Exception { return new SpringHello(); } @Override public Class<?> getObjectType() { return SpringHello.class; } @Override public boolean isSingleton() { return true; } }
上述的代码实际上对应连个bean对象
-
1.beanName为“demo”,bean对象的getObject()方法所返回的为SpringHello对象。
-
2.beanName为“&demo”,bean对象为Demo类的实例对象。
-
11.FactoryBean和BeanFactory。
- FactoryBean对象本身也是一个bean对象,同时也相当于是一个bean工厂,可以创建出其它的bean对象。
- BeanFactory是Spring的一个容器,是一个大型的工厂,可以创建出各样的bean。
- FactoryBean机制被广泛的应用在Spring内部和Spring与第三方框架整合的过程中。
12.ApplicationContext是什么?
- ApplicationContext是比BeanFactory更强大的Spring容器,它即可以创建bean、获取bean,还支持国际化、事件广播、获取资源等BeanFactory不具备的功能。
- ApplicationContext是BeanFactory的子类。即拥有BeanFactory的功能。
- ApplicationContext所继承的接口:
- EnvironmentCapable:继承了这个接口,就拥有了可以获取系统环境变量的功能。可以通过ApplicationContext来获取系统环境变量和JVM环境变量。
- ListableBeanFactory:继承了这个接口就,就拥有了获取所有beanNames、判断某个beanName是否存在BeanDedinition对象、统计BeanDefinition个数、获取某个类型对象的beanNames功能。
- HierarchicalBeanFactory:继承这个接口,就拥有了获取父 BeanFactory、判断某个name是否存在bean的功能。
- MessageSource:继承这个接口,就拥有了国际化功能,比如可以直接利用MessageSource对象获取某个国际化资源(比如不同国际所对应的字符等)
- ApplicationEventPublisher:继承了这个接口,就拥有了事件发布功能,可以发布事件,这是ApplicationContext相比较与BeanFactory突出、常用的功能。
- ResourcePatternResolver:继承这个接口,就拥有了加载并获取资源的功能,这里的资源可以是图片、文件等某个URL资源都可以。
13.BeanPostProcessor是什么?
- BeanPostProcessor是Spring提供的一种扩展机制,可以利用该机制对bean进行定制化加工,在Spring底层源码实现中,也广泛运用到了该机制,BeanPostProcessor也叫做bean的后置处理器。
- BeanPostProcessor是Spring提供的一个接口,我们定义一个后置处理器就是提供一个类实现该接口。在Spring中还存在一些类继承了BeanPostPocesser,这些子接口是在BeanPostProcessor的基础上扩展了一些其他功能。
- BeanPostProcessor中的方法:
- postProcessorBeforeInitializatio:初始化方法前,表示可以利用这个方法在初始化前对bean进行自定义加工。
- postProcessorAfterInitializatio:初始化方法后,表示可以利用这个方法在初始化后对bean进行自定义加工。
14.InstantiationAwareBeanPostProcessor是什么?
- InstantiationAwareBeanPostProcessor是BeanPostProcessor的一个子接口。
- InstantiationAwareBeanPostProcessor中的方法:
- postProcessorBeforeInitializatio:初始化方法前,表示可以利用这个方法在初始化前对bean进行自定义加工。
- postProcessorAfterInitializatio:初始化方法后,表示可以利用这个方法在初始化后对bean进行自定义加工。
- postProcessorProperties:属性注入后。
15.AOP是什么?
- AOP就是面向切面编程。
- AOP是一种非常适合在无需修改业务代码的前提下,对某个功能或者某个业务增加统一的功能。比如日志记录、权限控制、事务管理等。
- AOP能很好的实现业务代码与辅助代码的解耦,提高开发效率。
- AOP中的核心概念:
- Advice:可以理解为通知、建议。在Spring中可以用来定义代理逻辑。
- Pointcut:表示切点,用来定义Advice对应的代理逻辑应用在哪个类、哪个方法上。
- Advisor:等于Advice+Pointcut,表示代理逻辑和切点的一个整体。我们可以通过定义或封装一个Advisor来定义切点和代理逻辑。
- Weaving:表示织入。将Advice代码逻辑在源码级别嵌入到切点的过程就叫做织入。
- Target:表示目标对象,也就是被代理对象。在AOP生成的代理对象中会持有目标对象。
- Join Point:表示连接点。在AOP中就是方法的执行点。
17.AOP的工作原理。
- AOP发生在Spring的bean周期中的bean的创建过程中:
- Spring生成bean时,先通过构造方法实例化一个普通对象,也就是target对象。
- 再对Target对象进行属性填充。
- 在初始化后步骤中,Spring会判断target对象有没有对应的切面。
- target对象如果有切面,就表示当前的target对象需要进行AOP。
- 通过Cglib和JDK动态代理机制为target对象生成一个代理对象,也就是最终的bean对象。bean对象中有一个target属性指向target对象。
- 在将bean对象存入单例池中。
18.JavaBean、SpringBean、对象之间的关系。
- JavaBean和SpringBean都是对象。
- JavaBean:就是对象属性私有化,并提供供外部调用的公有的get()、set()方法。不允许调用者直接访问属性。(封装)
- SpringBean:被Spring管理的bean,是普通对象的代理对象。
19.单例bean、单例模式的区别
- 单例bean:同类型、同对象名的对象只有一个。
- 单例模式:一个类只能生成一个实例对象。每次getBean()的时候都会获取此实例对象,不会重新new一个实例对象。
20.什么是单例池?
- 单例池Spring就是用来存放单例bean的容器。
- 单例池的底层是一个ConcurrentHashMap<String,Object> singletonObject。
- ConcurrentHashMap<String,Object> singletonObject 中的的key就是bean的名字,value就是bean。
21.ApplicationContext的实现类。
- 注解:
- AnnotationConfigApplicationContext:参数可以传入扫描路径或配置类对象。
-
@Configuration @ComponentScan("com.wlj") public class AnnotConfig { }
-
public class SpringHello { private String name = "wangLiJun"; public static void main(String[] args) { //AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.wlj"); AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotConfig.class); Demo demo = applicationContext.getBean("demo", Demo.class); System.out.println(demo.getName()); } }
- 配置文件:
- ClassPathXmlApplicationContext:只能从classpath路径获取配置文件。
- FileSystemXmlApplicationContext:可以解析绝对路径配置文件或相对于工程目录的相对路径配置文件。
public class SpringHello { private String name = "wangLiJun"; public static void main(String[] args) { //ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("appContext.xml"); FileSystemXmlApplicationContext applicationContext = new FileSystemXmlApplicationContext("C:\\Users\\17587\\IdeaProjects\\spring-hello\\src\\main\\resources\\appContext.xml"); SpringHello springHello = applicationContext.getBean("springHello", SpringHello.class); System.out.println(springHello.name); } }