框架学习1:Spring常见问题

1. 什么是Spring框架

  1. 定义:一款开源的轻量级 Java 开发框架,我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合。
  2. 用途:提高开发人员的开发效率以及系统的可维护性;不重新造轮子,开箱即用!
  3. 核心功能:IoCAOP
    (1):可以很方便地对数据库进行访问
    (2):可以很方便地集成第三方组件(电子邮件,任务,调度,缓存等等)
    (3):对单元测试支持比较好
    (4):支持 RESTful Java 应用程序的开发。

2. 列举一些重要的 Spring 模块?

2.1. Data Access/Integration(数据访问和整合)

1)spring-jdbc:提供对数据库访问的抽象JDBC(屏蔽数据库的影响)
2)spring-orm :ORM框架支持
3)spring-oxm :OXM 框架支持
4)spring-jms:Java 消息服务
5)spring-transaction:提供事务支持

2.2. Web(网页)

1)spring-websocket:提供对websocket的支持,可以让客户端和服务端进行双向通信。
2)spring-servlet:为springmvc的实现做好铺垫
2)spring-web:对web功能的实现提供最基础的支持
3)spring-webflux:提供对webflux的支持,新的响应式框架

2.3. Spring AOP+Spring Aspects

  1. Spring AOP:提供面向切面编程的实现
  2. Spring Aspects:与为与Aspects的继承提供支持

2.4 Spring Core:核心模块

  1. Spring其他的所有功能都需要依赖该类库,主要提供loc依赖注入功能的支持。

2.5 Spring Test

  1. spring提倡测试驱动开发。
  2. 有了控制反转的帮助,单元测试和集合测试变得很简单。
  3. 支持的测试模块:JUnit(单元测试框架);TestNG;Mockito等

3. Spring IOC & AOP

3.1 谈谈自己对于 Spring IoC 的了解?

  1. IoC:控制反转,是一种设计思想,不是一个具体的技术实现。
    (1):控制:对象创建(实例化和管理)的权力。
    (2):控制权交给外部环境(Spring框架和loc容器)
  2. 核心思想:将原本在程序中手动创建对象的控制权,交给Spring框架来管理
    (1):对象之间的耦合度或者说依赖程度降低;
    (2):资源变的容易管理;比如你用 Spring 容器提供的话很容易就可以实现一个单例。
  3. 区别展示:AOP和一般的依赖新建

3.2 谈谈自己对于 AOP 的了解

  1. AOP(Aspect-Oriented Programming:面向切面编程):能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来
    (1):便于减少系统的重复代码,
    (2):降低模块间的耦合度,
    (3):并有利于未来的可拓展性和可维护性。
  2. 解决的问题
    (1):通过上面的分析可以发现,AOP 主要用来解决:在不改变原有业务逻辑的情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。
  3. AOP 为什么叫面向切面编程
    (1):切 :指的是横切逻辑,原有业务逻辑代码不动,只能操作横切逻辑代码,所以面向横切逻辑
    (2):面 :横切逻辑代码往往要影响的是很多个方法,每个方法如同一个点,多个点构成一个面。这里有一个面的概念.

3.3 Spring AOP 和 AspectJ AOP 有什么区别?

  1. Spring AOP :属于运行时增强,基于代理(Proxying),
  2. AspectJ 是编译时增强:基于字节码操作(Bytecode Manipulation)

3.4 Spring AOP的实现–动态代理

Spirng默认采用:JDK动态代理实现机制;如果实现类不存在接口,那么就会被强制使用CGLib动态代理

3.4.1 静态代理

  1. 定义:通过申明一个明确的代理类来访问源对象,避免对源对象代码的修改。
  2. 步骤
    1)定义人的接口
    2)实现人的接口,定义学生实现类
    3)实现人的接口,定义人的代理类(代理类代理学生对象,并且通过重写其方法,增加一些功能)
    2)实现人的接口,定义医生实现类
    3)实现人的接口,定义医生的代理类(代理类代理医生对象,并且通过重写其方法,增加一些功能)
  3. 缺点
    1)每需要额外代理一个对象的时候,就需要一个对象的实现类和代理类,所需要的代理类太多了。
    2)会存在大量的冗余的代理类,这里演示了2个接口,如果有10个接口,就必须定义10个代理类。
    3)不易维护,一旦接口更改代理类和目标类都需要更改
    4)需要一个通用的代理类,只要一个代理类就行,然后把实现类给传递进行就可以了。

3.4.2 基于JDK的动态代理(代码来源文献7)

//创建一个JdkProxy类,用于统一代理:
public class JdkProxy implements InvocationHandler {

    private Object bean;

    public JdkProxy(Object bean) {
        this.bean = bean;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if (methodName.equals("wakeup")){
            System.out.println("早安~~~");
        }else if(methodName.equals("sleep")){
            System.out.println("晚安~~~");
        }

        return method.invoke(bean, args);
    }
}

//执行代码:
public static void main(String[] args) {
    JdkProxy proxy = new JdkProxy(new Student("张三"));
    Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);
    student.wakeup();
    student.sleep();

    proxy = new JdkProxy(new Doctor("王教授"));
    Person doctor = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);
    doctor.wakeup();
    doctor.sleep();

    proxy = new JdkProxy(new Dog("旺旺"));
    Animal dog = (Animal) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Animal.class}, proxy);
    dog.wakeup();
    dog.sleep();

    proxy = new JdkProxy(new Cat("咪咪"));
    Animal cat = (Animal) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Animal.class}, proxy);
    cat.wakeup();
    cat.sleep();
}
  1. 步骤
    1)定义人的接口
    2)实现人的接口,定义学生实现类
    3)实现人的接口,定义通用的代理类(代理类代理XX对象,并且通过重写其方法,增加一些功能)
  2. 特性
    1)核心类:动态代理核心使用了两个java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。前者是代理实现类,后者是需要实现的接口。
    2)与静态代理区别:只需要书写一个通用代理类,然后把需要代理的类传进代理类就可以使用。
    3)特殊性:JDK动态代理是需要声明接口的,创建一个动态代理类必须得给这个”虚拟“的类一个接口,即这里举例的person接口。JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力。

3.4.3 基于Cglib的动态代理

//创建CglibProxy类,用于统一代理:
public class CglibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    private Object bean;

    public CglibProxy(Object bean) {
        this.bean = bean;
    }
//
//与JDK动态代理的区别
    public Object getProxy(){
        //设置需要创建子类的类
        enhancer.setSuperclass(bean.getClass());
        enhancer.setCallback(this);
        //通过字节码技术动态创建子类实例
        return enhancer.create();
    }
//    
    //实现MethodInterceptor接口方法
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        String methodName = method.getName();
        if (methodName.equals("wakeup")){
            System.out.println("早安~~~");
        }else if(methodName.equals("sleep")){
            System.out.println("晚安~~~");
        }

        //调用原bean的方法
        return method.invoke(bean,args);
    }
}
//执行代码:
public static void main(String[] args) {
    CglibProxy proxy = new CglibProxy(new Student("张三"));
    Student student = (Student) proxy.getProxy();
    student.wakeup();
    student.sleep();

    proxy = new CglibProxy(new Doctor("王教授"));
    Doctor doctor = (Doctor) proxy.getProxy();
    doctor.wakeup();
    doctor.sleep();

    proxy = new CglibProxy(new Dog("旺旺"));
    Dog dog = (Dog) proxy.getProxy();
    dog.wakeup();
    dog.sleep();

    proxy = new CglibProxy(new Cat("咪咪"));
    Cat cat = (Cat) proxy.getProxy();
    cat.wakeup();
    cat.sleep();
}

  1. 步骤
    1)定义人的接口
    2)实现人的接口,定义学生实现类
    3)实现人的接口,定义通用的代理类(代理类代理XX对象,并且通过重写其方法,增加一些功能)
  2. 特性
    1)Cglib动态代理和JDK几乎一模一样,不过有几点小区别
    2)在JDK动态代理中,被代理的实现类一定要有接口,但是Cglib就不需要有接口,因为多了两行,生成了子类。
    3)CGLib动态代理是通过字节码底层继承要代理类来实现。

4. Spring bean

4.1 Bean是什么

  1. bean 代指的就是那些被 IoC 容器所管理的对象。
  2. 我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据来定义的。配置元数据可以是 XML 文件注解或者 Java 配置类

4.3. bean 的作用域有哪些?

(1):singleton :唯一bean实例,Spring中的bean默认都是单例的,对单例设计模式的应用。
(2):prototype:每次请求都会创建一个新的bean实例。
(3):request:每一次http请求都会生成一个bean,仅在当前的Http session内有效
(4):session:

4.4. bean的作用域配置方式有哪几种?

4.5. 单例 bean 的线程安全问题了解吗?

  1. 在项目中很少使用多线程,但是是存在线程安全问题的
  2. 主要原因是:多个线程操作同一个对象的时候是存在资源竞争的。
  3. 解决方法:
    (1):在bean中尽量避免定义可变的成员变量
    (2):在类中定义一个ThreadLocal成员变量,将需要使用的可变成员变量保存在ThreadLocal中(每一个线程保存一份,一种解决思路)

4.6. @Component 和 @Bean 的区别是什么?

  1. @Component
    1)注解作用于类
    2)通过类路径扫描来自动侦测以及自动装配到 Spring 容器中
  2. @Bean
    1)注解作用于方法
    2)@Bean告诉了 Spring 这是某个类的实例,当我需要用它的时候还给我。
    3)注解的自定义性更强,例如在引用第三方库中的类需要装配到Spring容器中,只能通过@Bean实现。也可以定义一些自定义的类。
  3. 举例说明
//使用Component对类进行申明,装配到Spring容器中
@Component
public class Student {
    private String name = "lkm";
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
//使用Bean对方法进行申明,装配到Spring容器中(当为第三方jar包时,只能使用Bean,配合配置Configuration使用)
@Configuration  //(告诉spring这是一个配置类)
@ComponentScan(value="com.forever")  //要扫描的包
public class MainConfig {
	//给容器注册一个bean;类型为返回值类型,id默认是用方法名作为id
	@Bean(value="person")
	public Person person01(){
		return new Person("lisi",20);
	}
}

4.7. 将一个类声明为 bean 的注解有哪些?

  1. 一般使用@Autowired注解自动装配bean。要想把类标识为可用于@Autowired注解自动装配的bean的类,需要下面几种注释(对于类进行的注解,分为三层):
    1)@Component:通用的注解。如果忘记了时放在那一层,用这个注解。
    2)@Repository:对应于持久层即Dao层,主要用于数据库相关的操作(啥也没有)
    3)@Service : 对应于服务层,主要涉及进一步的复杂逻辑,需要使用到Dao层。(@Autowired Dao层的类)
    4)@Controller:控制层,即调用Service层的信息返回数据给前端页面。(@Autowired Service层的类)

4.8. Bean的生命周期?

5. Spring MVC

5.1 Spring MVC的大体认识?

  1. MVC是模型,视图和控制器的简写。MVC 是一种设计模式,Spring MVC 是一款很优秀的 MVC 框架。
  2. 核心思想:通过将业务逻辑,数据处理和显示分离
    MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。

5.2 SpringMVC 工作原理了解吗?

  1. 自己着重看一看。
  1. 过滤器(Filter)与拦截器(Interceptor)的区别:
    1)过滤器:过滤器,是在java web中将你传入的request、response提前过滤掉一些信息,或者提前设置一些参数,之后再进行业务操作。就是在请求前进行过滤与设置(比如登录和权限分配就是在这里起作用的)
    2)拦截器:在你的Service或者一个方法前调用一个方法,或者在方法后调用一个方法。(比如动态代理,就是指定某些Service进行操作)
    3)拦截器与过滤器触发时机不一样: 过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。过滤器包裹servlet,servlet包裹住拦截器。
    4)拦截器的使用场景:
    (1)日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
    (2)权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
    (3)性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

6. Spring 框架中用到了哪些设计模式?

  1. 工厂设计模式:使用工厂模式通过BeanFactory,Applicationcontext创建bean对象。
  2. 代理设计模块:Spring AOP功能的实现。
  3. 单例设计模式:Spring中的Bean默认都是单例的。
  4. 模板方法模式:Spring中的jdbcTemplate,hibernateTemplate等以 Template结尾的对数据库操作的类,他们就使用了模板模式。
  5. 观察者模式:Spring事件驱动模型就是观察值模式很经典的一个应用。
  6. 适配器模式 :Spring AOP的增强或通知(Advice)使用到了适配器模式Spring MVC中也是用到了适配器模式适配Controller

7. 你们项目中为什么使用Spring框架?

  1. 轻量:Spring 是轻量的,基本的版本大约2MB。
  2. 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
  3. 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
  4. 容器:Spring 包含并管理应用中对象的生命周期和配置。
  5. MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
  6. 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
  7. 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。

8. 为什么使用SpringBoot框架?

  1. Spring与SpringBoot的关系
    1)SpringBoot提供了一种快速使用Spring的方法;其核心还是使用的Spring,只是中间进行了简化。
    2)SpringBoot并不是对Spring功能上的增强,而是对提供了一种快速使用Spring的方式。
  2. Spring的缺点
    1)配置繁琐:Spring组件代码是轻量级的,但是配置确实重量级的;XML配置;基于注解的配置和基于JAVA的配置。
    2)依赖繁琐:项目的依赖管理,需要导入哪些库的坐标,选错了依赖的版本,兼容会出问题。
  3. SpringBoot的优点
    1)自动配置:应用程序启动后,会进行自动配置(约定大于配置,即能用默认就用默认配置)
    2)起步依赖:本质上是一个Maven项目对象模型,定义了对其他库的传递依赖。(具备某种功能的坐标打包到了一起,提供一些默认的功能)
    3)辅助功能:安全指标,健康检测和外部配置等非功能性特性。

8. 为什么使用SpringCloud框架?

  1. 由于的应用随着系统复杂度的增高,会暴露出各种各样的问题
  2. 近些年来,微服务架构逐渐取代了单体架构,且这种趋势将会越来越流行。Spring Cloud是目前最常用的微服务开发框架,已经在企业级开发中大量的应用。
  3. SpringCloud是在SpringBoot的基础上开发的,不能脱离。即Spring>SpringBoot>SpringCloud

7. Spring 事务

7.1 Spring 管理事务的方式有几种?

  1. 编程式事务: 在代码中硬编码(不推荐使用) ,但是会更加灵活。采用TransactionTemplate(推荐使用)。
@Test
public void testTransactionTemplate(){
	jdbcTemplate = new JdbcTemplate(dataSource);
    int i = jdbcTemplate.queryForInt(COUNT_SQL);  
    System.out.println("表中记录总数:"+i);
	//构造函数初始化TransactionTemplate
	TransactionTemplate template = new TransactionTemplate(txManager);
	template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);  
	//重写execute方法实现事务管理
	template.execute(new TransactionCallbackWithoutResult() {
		@Override
		protected void doInTransactionWithoutResult(TransactionStatus status) {
			jdbcTemplate.update(INSERT_SQL, "饿死");   //字段sd为int型,所以插入肯定失败报异常,自动回滚,代表TransactionTemplate自动管理事务
		}}
	);
	i = jdbcTemplate.queryForInt(COUNT_SQL);  
    System.out.println("表中记录总数:"+i);
}
  1. 声明式事务 : 在 XML 配置文件中配置或者直接基于注解(推荐使用) ;通过AOP实现。
    1)与编程式事务优点:可知编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式不会影响业务逻辑的实现。
    2)代码案例展示
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)

在方法,接口和实现类上面添加注解,能够完成。
3)特点:
(1) 如果在接口、实现类或方法上都指定了**@Transactional** 注解,则优先级顺序为方法>实现类>接口;
(2)建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用。基于JDK代理机制没问题,CGLIB代理(继承)机制时就会遇到问题。

7.2 Spring 事务中哪几种事务传播行为?

事务传播行为是为了解决业务层方法之间互相调用的事务问题。

  1. TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  2. TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  3. TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价
  4. TransactionDefinition.PROPAGATION_MANDATORY :如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(用的很少)

7.3 Spring 事务中的隔离级别有哪几种?

  1. TransactionDefinition.ISOLATION_DEFAULT :使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别.
  2. TransactionDefinition.ISOLATION_READ_UNCOMMITTED :未提交, 最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  3. TransactionDefinition.ISOLATION_READ_COMMITTED : 已经提交, 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
  4. TransactionDefinition.ISOLATION_REPEATABLE_READ : 可重复读, 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  5. TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

7.4 @Transactional(rollbackFor = Exception.class)注解了解吗?

  1. 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。

7.4.1 @Transactional

  1. 当 @Transactional 注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性
  2. 类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。

7.4.2 @Transactional 的rollbackFor属性

  1. @Transactional 注解中如果不配置rollbackFor属性,只会在遇到RuntimeException的时候才会回滚。
  2. rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚

8. JPA

8.1 使用 JPA 在数据库中非持久化一个字段?

  1. 这个字段不被持久化,也就是不被数据库存储怎么办
//1)使用注解:比较常用
@Transient
String transient4; // not persistent because of @Transient

参考文献

  1. https://javaguide.cn/
  2. https://blog.csdn.net/qq_42405666/article/details/107671099
  3. https://blog.csdn.net/liaohaojian/article/details/70139151
  4. https://blog.csdn.net/weixin_44502804/article/details/93139550
  5. 使用@Bean来导入第三方组件
  6. 2年java,华为面试,一面 挂
  7. Spring Cloud入门-十分钟了解Spring Cloud
    动态代理大揭秘,带你彻底弄清楚动态代理!
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值