spring 注入的方式
Spring实例注入的三种方式:
1.属性注入,即使用注解注入。
使用@Autowired、@Resource或@Inject注解注入。
1.1@Autowired:Spring提供,默认按照类型装配。必须要求要注入的对象存在,
如果要允许空值,设置其required属性为true
1.2@Resource:J2EE提供,默认按照名称装配,名称可以通过name属性指定,默认取字段名进行查找并完成注入。
找不到名称时才会按照类型进行装配。所以@Resource的作用其实和@Autowired类似,只不过是注入方式不同。
但是属性注入是不推荐的。
2.set方法注入。
@Controller
public class FooController {
private FooService fooService;
//使用方式上同,略
@Autowired
public void setFooService(FooService fooService) {
this.fooService = fooService;
}
}
3.构造方法注入。
@Controller
public class FooController {
private final FooService fooService;
@Autowired
public FooController(FooService fooService) {
this.fooService = fooService;
}
}
使用构造方法注入更好,构造注入方法有以下几个优势:
4.1:依赖不可变。通过构造方法注入的bean以后无法修改。
4.2:依赖不为空。构造方法注入时会自动检查注入的对象是否为空。
4.3:完全初始化。拿到的是完全初始化的对象。
什么是Spring IoC容器
Spring IoC负责创建对象、管理对象(通过依赖注入(DI)、装配对象、配置对象,并且管理这些对象的整个生命周期
IoC的优点是什么
IoC或依赖注入把应用的代码量降到最低;
它使应用容易测试,单元测试不再需要单例和JNDI查找机制;
最小的代价和最小的侵入性使松散耦合得以实现;
IoC容器支持加载服务时的饿汉式初始化和懒加载。
什么是依赖注入?
即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中
- 谁依赖于谁:
当然是应用程序依赖于IoC容器; - 为什么需要依赖:
应用程序需要IoC容器来提供对象需要的外部资源; - 谁注入谁:
很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象; - 注入了什么:
就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)
spring中有多少种IOC容器?
BeanFactory-BeanFactory就像一个包含bean集合的工厂类。它会在客户端要求时实例化bean。
ApplicationContext-ApplicationContext 接口扩展了BeanFactory接口。它在BeanFactory基础上提供了一些额外的功能。
Spring IoC的实现机制
Spring中的IoC的实现原理就是工厂模式加反射机制。
interface Fruit {
public abstract void eat();
}
class Apple implements Fruit {
public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit {
public void eat(){
System.out.println("Orange");
}
}
class Factory {
public static Fruit getInstance(String ClassName) {
Fruit f=null;
try {
f=(Fruit)Class.forName(ClassName).newInstance();
}
catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client {
public static void main(String[] a) {
Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple");
if(f!=null){
f.eat();
}
}
}
什么是spring bean?
spring提供了哪些配置方式?
@Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 Bean 间依赖关系。
相当于spring的配置文件XML
例如:
@Configuration
public class StudentConfig {
@Bean
public StudentBean myStudent() {
return new StudentBean();
}
}
spring支持集中bean scope?
Spring支持以下6中bean scopes:
- singleton: 单例模式(默认值),在Spring容器中只会创建一个实例。每个Spring IoC容器仅有一个单实例
- prototype: 原型模式,每次通过Spring容器获取bean时,容器都会新建一个实例。 每次请求都会产生一个新的实例
request: 每次HTTP请求都会创建一个实例,但只在http request范围有效。
session: 在http session生命周期内,共享一个实例,不同session有不同的实例。
application: 在ServletContext生命周期内,只有一个实例。
webSocket: 在webSocket范围内只有一个实例。
Request、Session、Application、WebSocket作用域仅在使用web感知的Spring ApplicationContext实现(如XmlWebApplicationContext)时可用。
@Resource和@Autowired区别对比
@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
1、共同点
两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法
2、不同点
(1)@Autowired
@Autowired为Spring提供的注解,需要导入包 org.springframework.beans.factory.annotation.Autowired;只按照byType注入。
public class TestServiceImpl {
// 下面两种@Autowired只要使用一种即可
@Autowired
private UserDao userDao; // 用于字段上
@Autowired
public void setUserDao(UserDao userDao) { // 用于属性的方法上
this.userDao = userDao;
}
}
@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。如下:
public class TestServiceImpl {
@Autowired
@Qualifier("userDao")
private UserDao userDao;
}
(2)@Resource
@Resource默认按照ByName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。
所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。
public class TestServiceImpl {
// 下面两种@Resource只要使用一种即可
@Resource(name="userDao")
private UserDao userDao; // 用于字段上
@Resource(name="userDao")
public void setUserDao(UserDao userDao) { // 用于属性的setter方法上
this.userDao = userDao;
}
}
@Resource装配顺序:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
@Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。
spring支持的事务管理类型
Spring支持两种类型的事务管理:
1、 程序化事务管理:在此过程中,在编程的帮助下管理事务。它为您提供极大的灵活性,但维护起来非常困难。
2、 声明式事务管理:在此,事务管理与业务代码分离。仅使用注解或基于 XML的配置来管理事务。
Filter、Interceptor、 Aspect之间的关系
//www.greatytc.com/p/28d75d839557
执行顺序
filter->interceptor->ControllerAdvice->aspect->controller
返回值顺序,或异常返回顺序
Controller->aspect->ControllerAdvice->Interceptor->Filter
什么是AOP
AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与OOP不同的抽象软件结构的视角,在OOP中, 我们以类(class)作为我们的基本单元, 而AOP中的基本单元是Aspect(切面)
什么是Aspect?
- Pointcut:切点用于定义 要对哪些Join point进行拦截。
切点分为execution方式和annotation方式。execution方式可以用路径表达式指定对哪些方法拦截,比如指定拦截add、search。annotation方式可以指定被哪些注解修饰的代码进行拦截。 - Advice:指要在连接点(Join Point)上执行的动作,即增强的逻辑,比如权限校验和、日志记录等。通知有各种类型,包括Around、Before、After、After returning、After throwing。
- Aspect:切面,被抽取出来的公共模块,可以用来会横切多个对象。Aspect切面可以看成 Pointcut切点 和 Advice通知 的结合,一个切面可以由多个切点和通知组成。
- Joint point:连接点,是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行。
- Weaving:织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。
Spring AOP and AspectJ AOP有什么区别?
- Spring AOP基于动态代理方式实现;
所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。 - AspectJ基于静态代理方式实现
也称为编译时增强,AOP框架会在编译阶段生成AOP代理类,并将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
Spring框架中的单例bean是线程安全的吗?
不,Spring框架中的单例bean不是线程安全的。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
① JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时,使用Proxy类来动态创建目标类的代理类(即最终真正的代理类,这个类继承自Proxy并实现了我们定义的接口),当代理对象调用真实对象的方法时, InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;
② 如果被代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。