• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

嗨吖呀

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

Java EE

  1. Spring

Spring的模块大概分为6个。分别是:

  1. Core Container(Spring的核心)【重要】
  2. AOP(面向切面变成)【重要】
  3. Messaging(消息发送的支持)
  4. Data Access/Integration(数据访问和集成)
  5. Web(主要是SpringWeb内容,包括MVC)【重要】
  6. Test(Spring测试支持,包含JUint等测试单元的支持)
  7. Instrumentation(设备支持,比如Tomcat的支持)

 

  1. spring框架的优点

Spring是一个轻量级的DI和AOP容器框架,它的优点主要有以下几点:

  • Spring是一个非侵入式框架,其目标是使应用程序代码对框架的依赖最小化,应用代码可以在没有Spring或者其他容器的情况下运行。
  • Spring提供了一个一致的编程模型,使应用直接使用POJO(Plain Ordinary Java Object)开发,从而可以使运行环境隔离开来。
  • Spring推动应用的设计风格向面向对象及面向接口编程转变,提高了代码的重用性和可测试性。
  • Spring改进了结构体系的选择,虽然作为应用平台,Spring可以帮助我们选择不同的技术实现,比如从Hibernate切换到其他的ORM工具,从Struts切换到Spring MVC,尽管我们通常不会这么做,但是我们在技术方案上选择使用Spring作为应用平台,Spring至少为我们提供了这种可能性的选择,从而降低了平台锁定风险。

 

  1. Spring的启动过程

 

  1. Spring用到的设计模式

  • 单例模式:bean默认为单例模式
  • 工厂模式:beanfactory就是简单工厂模式的体现,用来创建对象实例
  • 代理模式:AOP用到的jdk动态代理和CGLIB字节码生成技术
  • 模板方法:用来解决代码重复问题,如RestTemplate,JmsTemplate,JpaTemplate。
  • 观察者模式:定义对象间一种一对多的依赖关系,当一个对象发生改变时,所有依赖他的对象都会被通知更新,如listener的实现

 

  1. SpringMVC处理请求流程

 

  1. springmvc和spring-boot区别

Spring MVC是基于Servlet的一个MVC框架,主要解决WEB开发的问题,但关于Spring的配置比较繁琐;而SpringBoot是在Spring的基础上做得一个扩展,Springboot的原则是:约定优于配置,可以极大地简化了spring的配置流程。SpringBoot对比Spring的一些优点包括:

  1. 提供嵌入式容器支持
  2. 使用命令java -jar独立运行jar
  3. 在外部容器中部署时,可以选择排除依赖关系以避免潜在的jar冲突
  4. 部署时灵活指定配置文件的选项
  5. 用于集成测试的随机端口生成

Spring 就像一个大家族,有众多衍生产品例如 Boot,Security,JPA等等。但他们的基础都是Spring 的 IOC 和 AOP,IOC提供了依赖注入的容器,而AOP解决了面向切面的编程,然后在此两者的基础上实现了其他衍生产品的高级功能;因为 Spring 的配置非常复杂,各种xml,properties处理起来比较繁琐。于是为了简化开发者的使用,Spring社区创造性地推出了Spring Boot,它遵循约定优于配置,极大降低了Spring使用门槛,但又不失Spring原本灵活强大的功能。

 

  1. Springboot

  • 定义:SpringBoot是由Pivotal团队在2013年开始研发、2014年4月发布第一个版本的全新开源的轻量级框架。它基于Spring4.0设计,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决。
  • 特征

    (1)可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;

    (2)内嵌Tomcat或Jetty等Servlet容器;

    (3)提供自动配置的"starter"项目对象模型(POMS)以简化Maven配置;

    (4)尽可能自动配置Spring容器;

    (5)提供准备好的特性,如指标、健康检查和外部化配置;

    (6)不需要XML配置。

  • 策略:开箱即用和约定优于配置
  1. 开箱即用,Outofbox,是指在开发过程中,通过在MAVEN项目的pom文件中添加相关依赖包,然后使用对应注解来代替繁琐的XML配置文件以管理对象的生命周期。这个特点使得开发人员摆脱了复杂的配置工作以及依赖的管理工作,更加专注于业务逻辑。
  2. 约定优于配置,Convention over configuration,是一种由SpringBoot本身来配置目标结构,由开发者在结构中添加信息的软件设计范式。这一特点虽降低了部分灵活性,增加了BUG定位的复杂性,但减少了开发人员需要做出决定的数量,同时减少了大量的XML配置,并且可以将代码编译、测试和打包等工作自动化。

 

  1. Spring中自动装配的方式

  • no:不进行自动装配,手动设置Bean的依赖关系。
  • byName:根据Bean的名字进行自动装配。
  • byType:根据Bean的类型进行自动装配。
  • constructor:类似于byType,不过是应用于构造器的参数,如果正好有一个Bean与构造器的参数类型相同则可以自动装配,否则会导致错误。
  • autodetect:如果有默认的构造器,则通过constructor的方式进行自动装配,否则使用byType的方式进行自动装配。

 

  1. @Autowired 和@Resource

  • 共同点:两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。
  • 不同点
  1. @Autowired为Spring提供的注解,只按照byType注入。@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。
  2. @Resource默认按照byName自动注入。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。

 

  1. Spring中Bean的作用域

 

  1. Bean的生命周期

如上图所示,Bean 的生命周期还是比较复杂的,下面来对上图每一个步骤做文字描述:

  1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
  2. Bean实例化后对将Bean的引入和值注入到Bean的属性中
  3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
  4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
  5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
  6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法。
  7. 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
  8. 如果Bean 实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
  9. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
  10. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。

 

  1. Spring Bean的加载过程

  • 获取 BeanName,对传入的 name 进行解析,转化为可以从 Map 中获取到 BeanDefinition 的 bean name。
  • 合并 Bean 定义,对父类的定义进行合并和覆盖,如果父类还有父类,会进行递归合并,以获取完整的 Bean 定义信息。
  • 实例化,使用构造或者工厂方法创建 Bean 实例。
  • 属性填充,寻找并且注入依赖,依赖的 Bean 还会递归调用 getBean 方法获取。
  • 初始化,调用自定义的初始化方法。
  • 获取最终的 Bean,如果是 FactoryBean 需要调用 getObject 方法,如果需要类型转换调用 TypeConverter 进行转化。

 

  1. IOC和DI

IoC叫控制反转,是Inversion of Control的缩写,DI(Dependency Injection)叫依赖注入,是对IoC更简单的诠释。控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的"控制反转"就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。

依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由容器负责,查找资源的逻辑应该从应用组件的代码中抽取出来,交给容器来完成。DI是对IoC更准确的描述,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。

一个类A需要用到接口B中的方法,那么就需要为类A和接口B建立关联或依赖关系,最原始的方法是在类A中创建一个接口B的实现类C的实例,但这种方法需要开发人员自行维护二者的依赖关系,也就是说当依赖关系发生变动的时候需要修改代码并重新构建整个系统。如果通过一个容器来管理这些对象以及对象的依赖关系,则只需要在类A中定义好用于关联接口B的方法(构造器或setter方法),将类A和接口B的实现类C放入容器中,通过对容器的配置来实现二者的关联。

依赖注入可以通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系,对于可选的依赖关系,则setter注入是更好的选择,setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。

  • 实现IOC的步骤
  1. 定义用来描述bean的配置的Java类
  2. 解析bean的配置,將bean的配置信息转换为BeanDefinition对象保存在内存中,spring中采用HashMap进行对象存储,其中会用到一些xml解析技术
  3. 遍历存放BeanDefinition的HashMap对象,逐条取出BeanDefinition对象,获取bean的配置信息,利用Java的反射机制实例化对象,將实例化后的对象保存在另外一个Map中即可。

 

  1. AOP

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事务。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB字节码生成技术。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

  • 动态代理应用场景:
  1. 统计每个 api 的请求耗时
  2. 统一的日志输出
  3. 校验被调用的 api 是否已经登录和权限鉴定
  4. Spring的 AOP 功能模块就是采用动态代理的机制来实现切面编程
  • JDK是基于反射机制,生成一个实现代理接口的匿名类,然后重写方法,实现方法的增强。它生成类的速度很快,但是运行时因为是基于反射,调用后续的类操作会很慢,而且他是只能针对接口编程的。
  • CGLIB是基于继承机制,继承被代理类,所以方法不要声明为final,然后重写父类方法达到增强了类的作用。它底层是基于asm第三方框架,是对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。生成类的速度慢,但是后续执行类的操作时候很快。可以针对类和接口。
  • 因为jdk是基于反射,CGLIB是基于字节码。所以性能上会有差异。在老版本CGLIB的速度是JDK速度的10倍左右,但是CGLIB启动类比JDK慢8倍左右,但是实际上JDK的速度在版本升级的时候每次都提高很多性能,而CGLIB仍止步不前。在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。
  • 具体应用:
    • 如果目标对象实现了接口,默认情况下是采用JDK动态代理实现AOP。
    • 如果目标对象没有实现接口,必须采用CGLIB库。

 

  1. 动态代理和静态代理的区别

代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

  • 代理模式的好处:
  1. 可以使真实角色的操作更加纯粹,不用去关心一些公共业务
  2. 公共业务交给了代理角色,实现了业务的分工
  3. 公共业务发生扩展的时候方便集中管理
  • 缺点:一个真实角色就会产生一个代理角色,代码量翻倍

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

 

public class ProxyInvocationHandler implements InvocationHandler {

//被代理的接口

private Object target;

 

public void setTarget(Object target) {

this.target = target;

}

 

public Object getProxy(){

return Proxy.newProxyInstance(this.getClass().getClassLoader(),

this.target.getClass().getInterfaces(),

this);

}

//处理代理实例,并返回结果

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

log(method.getName());

Object res= method.invoke(target,args);

//fare();

return res;

}

 

public void log(String msg){

System.out.println("执行了"+msg+"方法");

}

}

 

  1. Spring中BeanFactory和ApplicationContext的区别

  • BeanFactory是spring中比较原始,比较古老的Factory,所以BeanFactory无法支持spring插件,例如:AOP、Web应用等功能。
  • ApplicationContext是BeanFactory的子类,因为BeanFactory无法满足不断更新的spring的需求,于是ApplicationContext就基本上代替了BeanFactory的工作,以一种更面向框架的工作方式以及对上下文进行分层和实现继承
  • 区别:
  1. 如果使用ApplicationContext,如果配置的bean是singleton,那么不管你有没有或想不想用它,它都会被实例化。好处是可以预先加载,坏处是浪费内存。
  2. BeanFactory,当使用BeanFactory实例化对象时,配置的bean不会马上被实例化,而是等到你使用该bean的时候(getBean)才会被实例化。好处是节约内存,坏处是速度比较慢。多用于移动设备的开发。
  3. 没有特殊要求的情况下,应该使用ApplicationContext完成。因为BeanFactory能完成的事情,ApplicationContext都能完成,并且提供了更多接近现在开发的功能。

 

  1. Spring中BeanFactory和FactoryBean的区别

BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似

 

  1. Spring支持的事务管理类型

Spring支持编程式事务管理和声明式事务管理。许多Spring框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务。

事务分为全局事务和局部事务。全局事务由应用服务器管理,需要底层服务器JTA支持(如WebLogic、WildFly等)。局部事务和底层采用的持久化方案有关,例如使用JDBC进行持久化时,需要使用Connetion对象来操作事务;而采用Hibernate进行持久化时,需要使用Session对象来操作事务。

这些事务的父接口都是PlatformTransactionManager。Spring的事务管理机制是一种典型的策略模式,PlatformTransactionManager代表事务管理接口,该接口定义了三个方法,该接口并不知道底层如何管理事务,但是它的实现类必须提供getTransaction()方法(开启事务)、commit()方法(提交事务)、rollback()方法(回滚事务)的多态实现,这样就可以用不同的实现类代表不同的事务管理策略。使用JTA全局事务策略时,需要底层应用服务器支持,而不同的应用服务器所提供的JTA全局事务可能存在细节上的差异,因此实际配置全局事务管理器是可能需要使用JtaTransactionManager的子类,如:WebLogicJtaTransactionManager(Oracle的WebLogic服务器提供)、UowJtaTransactionManager(IBM的WebSphere服务器提供)等。

 

  1. Spring事务的传播级别

 

  1. Spring MVC注解的优点

  2. XML配置起来有时候冗长,此时注解可能是更好的选择,如jpa的实体映射;注解在处理一些不变的元数据时有时候比XML方便的多,比如springmvc的数据绑定,如果用xml写的代码会多的多;
  3. 注解最大的好处就是简化了XML配置;其实大部分注解一旦确定后很少会改变,所以在一些中小项目中使用注解反而提供了开发效率;
  4. 注解相对于XML的另一个好处是类型安全的,XML只能在运行期才能发现问题。

 

  1. Java注解实现

Java EE下用Spring boot框架后,开始面向注解编程,可以说Spring boot就是建立在注解之上。

  • Java 注解(Annotation)又称 Java 标注,是JDK5.0引入的一种注释机制。 注解是元数据的一种形式,提供有关于程序但不属于程序本身的数据。注解对它们注解的代码的操作没有直接影响。
  • Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和着任何元数据(metadata)的途径和方法。Annotion(注解)是一个接口,程序可以通过反射来获取指定程序元素的Annotion对象,然后通过Annotion对象来获取注解里面的元数据。

注解可以实现以下功能:

  1. 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等
  2. 跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2依赖注入,未来java开发,将大量注解配置,具有很大用处;
  3. 在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

/*

*定义一个注解

*/

@Target({ElementType.TYPE,ElementType.FIELD})

@Retention(RetentionPolicy.RUNTIME)

public @interface Length {

int max();

int min();

String errorMsg();

}

 

/*

*使用上面的注解

*/

class Teacher {

private Long id;

private String name;

@Length(min =11, max =11, errorMsg ="传入的手机号长度有误,必须为11位")

private String mobilephone;

}

 

  1. Spring典型注解

@Controller,@Service,@Repository都有带@Component父注解,四个注解都可以说成是Component级别的注解,Spring框架自动扫描的注解也是检测是否有Component注解标记。把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>。

  • @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
  • @Repository 用于持久层,数据库访问层。当Service需要使用Spring创建的名字叫"userDao"的UserDaoImpl实例时,就可以使用@Resource(name = "userDao")注解告诉Spring,Spring把创建好的userDao注入给Service即可。
  • @Service 用于服务层,处理业务逻辑。@Service("userService")注解是告诉Spring,当Spring要创建UserServiceImpl的的实例时,bean的名字必须叫做"userService",这样当Action需要使用UserServiceImpl的的实例时,就可以由Spring创建好的"userService",然后注入给Action。
  • @Controller 用于控制层,用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法。通俗来说,被Controller标记的类就是一个控制器,这个类中的方法,就是相应的动作。

 

  1. @Controller和@RestController

@RestController注解相当于@ResponseBody + @Controller合在一起的作用

1) 如果只是使用@RestController注解Controller,则Controller中的方法无法返回jsp页面,或者html,配置的视图解析器 InternalResourceViewResolver不起作用,返回的内容就是Return 里的内容。

2) 如果需要返回到指定页面,则需要用 @Controller配合视图解析器InternalResourceViewResolver才行。

如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。

 

  1. SpringMVC的Controller是单例还是多例,有没有并发安全问题,如何解决?

  • Controller默认是单例,如果定义了成员变量就有并发问题,单例是不安全的,会导致属性重复使用。可以通过@Scope("prototype")设置为多例模式。
  • 解决方案
  1. 不要在controller中定义成员变量。
  2. 万一必须要定义一个非静态成员变量时候,则通过注解@Scope("prototype"),将其设置为多例模式。
  3. 在Controller中使用ThreadLocal变量

 

  1. Bean在什么时候被实例化?

  • 对于Prototype:在第一次请求的时候才被实例化的
  • 对于Singleton:
  1. 一般在IoC容器启动的时候就被实例化,然后被缓存在内存中
  2. 如果bean标签中有设置lazy-init=true,则会在第一次请求时才会被实例化,而不是在容器启动的时候就被实例化
  3. 但是,当一个懒实例化的Bean依赖了一个非懒实例化的Bean,那么IOC容器在启动的时候也会实例化这个Bean,因为它必须满足单例的依赖性

 

 

posted on 2021-08-24 20:59  嗨吖呀  阅读(120)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3