Spring的核心功能是轻量级容器,帮我们管理业务对象,对象的生命周期,以及对象和对象之间的关系,他有两个核心组件,就是IOC(依赖注入)和AOP(面向切面编程)
1.什么是loc?
loc是控制反转spring来创建对象,管理对象(装配对象,配置对象),并且管理对象的生命周期
Spring 中的 IOC 的实现原理就是工厂模式加反射机制
依赖注入是指在Spring创建对象的过程中,把对象依赖的属性注入到对象中
2.IOC容器在Spring中的实现
1.BeanFactory:是IOC的基本实现,Spring内部容器使用,不提供给开发人员使用
2.ApplicationContext:BeanFactory的子接口,面向Spring的使用者
3.ApplicationContext的子类:BeanFactory的主要实现类
3.依赖注入的实现方式
1.构造器注入:将被依赖对象通过构造函数的参数注入给依赖对象,并且在初始化对象的时候注入
<bean id="studentTwo" class="com.atguigu.spring.bean.Student">
<!-- name属性:指定属性名-->
<!-- index属性:指定参数所在位置的索引(从0开始)-->
<constructor-arg value="1002"></constructor-arg>
<constructor-arg value="李四"></constructor-arg>
<constructor-arg value="33" name="age"></constructor-arg>
<constructor-arg value="女"></constructor-arg>
</bean>
2.Setter方法注入:通过调用成员变量提供的 setter 函数将被依赖对象注入给依赖类
<bean id="studentOne" class="com.atguigu.spring.bean.Student">
<!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
<!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
<!-- value属性:指定属性值 -->
<property name="id" value="1001"></property>
<property name="name" value="张三"></property>
<property name="age" value="23"></property>
<property name="sex" value="男"></property>
</bean>
3.注解注入:使用@Autowired和@Resource等注解注入
4.基于XML管理bean
1.在Spring的配置文件中配置bean
<!--
配置HelloWorld所对应的bean,即将HelloWorld的对象交给Spring的IOC容器管理
通过bean标签配置IOC容器所管理的bean
属性:
id:设置bean的唯一标识
class:设置bean所对应类型的全类名
-->
<bean id="helloworld" class="com.atguigu.spring.bean.HelloWorld"></bean>
2.获取bean
2.1根据id获取bean
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld helloworld = (HelloWorld) ac.getBean("helloworld");
bean.sayHello();
2.2 根据类型获取bean
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld bean = ac.getBean(HelloWorld.class);
bean.sayHello();
2.3 根据id和类型获取bean
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld bean = ac.getBean("helloworld", HelloWorld.class);
bean.sayHello();
5.bean的作用域
在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围
singleton(默认):bean在IOC容器中只有一个实例,Spring 在读取 xml 文件的时候,就会创建对象
prototype:这个bean在IOC容器中有多个实例,每一次访问该对象的时候,Spring 容器都会创建这个对象
request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
session:在一个http session中一个bean定义对应一个实例,该作用域仅在基于web的Spring ApplicationContext情形下有效
global-session:在一个全局的http session中一个bean定义对应一个实例,该作用域仅在基于web的Spring ApplicationContext情形下有效
<!-- scope属性:取值singleton(默认值),bean在IOC容器中只有一个实例,IOC容器初始化时创建 对象 -->
<!-- scope属性:取值prototype,bean在IOC容器中可以有多个实例,getBean()时创建对象 -->
<bean class="com.atguigu.bean.User" scope="prototype"></bean>
6.bean的生命周期
1.bean对象的实例化(调用无参构造器)
2.bean的属性设值
3.bean的初始化
4.bean的使用
5.bean的销毁
7.基于xml的自动装配
1.no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean
2.byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配
3.byType:通过参数的数据类型进行自动装配
<bean id="userController"
class="com.atguigu.autowire.xml.controller.UserController" autowire="byType">
</bean>
4.constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
<bean id="userController"
class="com.atguigu.autowire.xml.controller.UserController" autowire="byName">
</bean>
5.autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配
8.基于注解的自动装配
注解装配在默认情况下是不开启的,为了使用注解装配,我们必须在Spring配置文件中配置 <context:annotation-config/>元素
@Component:将类标识为普通组件
@Controller:将类标识为控制层组件
@Service:将类标识为业务层组件
@Repository:将类标识为持久层组件
@Controller、@Service、@Repository这三个注解只是在@Component注解的基础上起了三个新的名字,它们本质上一样,让我们能够便于分辨组件的作用
@AutoWired默认按照bean的类型进行自动装配
@Resource中的name和type,如果指定 name 属性,则按实例名称进行装配,如果指定 type 属性,则按 Bean 类型进行装配,如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出NoSuchBeanDefinitionException 异常
@Qualifier:和@AutoWired注解配合使用,会将默认的按Bean类型装配修改为按Bean的实例名称装配,Bean的实例名称由@Qualifier注解的参数指定
9.Spring支持的事务管理类型, spring 事务实现方式有哪些?
编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护
声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务
10.Spring中如何处理线程并发
将变量放入ThreadLocal中,ThreadLocal为每个多线程提供了一个独立的变量副本,隔离了数据访问冲突
11.事务的失效场景
1.事务方法的修饰符非public导致事务失效
2.@Transactional注解的方法抛出的异常不是spring的事务支持的异常,导致事务失效
3.catch掉异常之后,没有再次抛出异常,导致事务失效
12.@Autoweried和@Resource的区别
@Autowired 和 @Resource 都是用来实现依赖注入的注解
查找顺序不同:@Autoweried是先根据类型再根据名称去查找,@Resource是先根据名称再根据类型去查找
支持的参数不同:@Autowired 只支持设置 1 个参数,而 @Resource 支持设置 7 个参数
13.什么是AOP?
通过预编译方式和运行期间的动态代理(动态代理是通过反射来实现的)实现在不改变源代码的情况下添加新的功能,只做增强不做改变,在事务处理、日志管理、权限控制方面应用
14.Aop的名词
切面(Aspect):切面是通知和切点的结合。通知和切点共同定义了切面的全部内容。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。
连接点(Join point):指方法,在Spring AOP中,一个连接点 总是 代表一个方法的执行。 应用可能有数以千计的时机应用通知。这些时机被称为连接点。连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
通知(Advice):在AOP术语中,切面的工作被称为通知。
切入点(Pointcut):切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点。
引入(Introduction):引入允许我们向现有类添加新方法或属性。
目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。它通常是一个代理对象。也有人把它叫做 被通知(adviced) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
织入(Weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。在目标对象的生命周期里有多少个点可以进行织入:
- 编译期:切面在目标类编译时被织入。AspectJ的织入编译器是以这种方式织入切面的。
- 类加载期:切面在目标类加载到JVM时被织入。需要特殊的类加载器,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入就支持以这种方式织入切面。
- 运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面
15.动态代理和静态代理
JDK动态代理:jdk的原生实现方式,需要被代理的目标类实现接口。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。JDK动态代理是Java提供的动态代理技术,可以在运行时创建接口的代理实例
cglib:通过继承被代理的目标类实现代理,所以不需要目标类实现接口。如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。CGLib动态代理采用底层的字节码技术,在运行时创建子类代理的实例
AspectJ:本质上是静态代理,将代码逻辑"织入"被代理的目标类编译得到的字节码文件,所以最终效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。
静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理
16.Aop的通知类型
前置通知:使用@Before注解标识,在被代理的目标方法前执行
返回通知:使用@AfterReturning注解标识,在被代理的目标方法成功结束后执行
异常通知:使用@AfterThrowing注解标识,在被代理的目标方法异常结束后执行
后置通知:使用@After注解标识,在被代理的目标方法最终结束后执行
环绕通知:使用@Around注解标识,使用try...catch...finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置