Spring

BeanFactory的作用

  1. BeFactory是Spring中一个非常核心的顶层接口。
  2. 他是Bean的工厂,主要职责就是生产bean.
  3. 实现了简单的工厂设计模式,通过getBean传入标识生产一个Bean.
  4. 他有非常多的实现类,每个工厂都有不同的职责(单一职责)功能。最强大的工厂是DefaultListableBeanFactory,Spring底层就是使用这个工厂生产bean的。

    BeanDefinition是什么

  5. 主要负责存储bean的定义信息,决定bean的生产方式。

  6. 后续beanFactory根据这些信息就能生产bean
    1. 比如实例化需要beanDefinition 中的 class信息,从而反射实例化对象。
    2. 比如lazy 则不会在ioc容器加载时创建bean.

配置bean:

  1. <bean class="com.bczhaoa.User" id="user" scope="singleton" lazy="false" autowire="none" >
  2. <property name="username" value="狗蛋"/>
  3. </bean>

beanDefinition就是存储这些配置信息的。

Spring - 图1

BeanFactory和ApplicationContext区别

  1. ApplicationContext实现了BeanFactory。
  2. BeanFactory功能单一,就是作为Bean的工厂生产Bean.
  3. ApplicationContext不生产Bean,而是通知FactoryBean来生成Bean.
  4. BeanFactory在启动的时候不会取实例化Bean,当Spring应用中有从容器拿Bean时才做实例化,即懒加载。
  5. APplicationContext在启动时就把所有Bean都生产了,也可以通过配置bean来实现懒加载。

    BeanFactory和FactoryBean区别

  6. BeanFactory是一个工厂,也就是一个容器。用来管理和生产Bean的。

  7. FactoryBean是一个Bean,所以他也是由BeanFactory来管理的。
  8. FactoryBean不是一个普通的Bean,他会表现出工厂模式的样子,是一个能生产对象的工厂Bean.
  9. 里面的getObject方法就是用来获取FactoryBean产生的对象。
  10. 如果需要获取工厂bean本身对象,getBean需要加 &前缀。

IOC容器的加载过程

  1. 从概念态到定义态
    1. 实例化一个ApplicationContext对象
    2. 调用bean工厂的后置处理器完成扫描。
    3. 循环解析出扫描出的信息,xml或注解解析。
    4. 实例化BeanDefinition,一个bean对应一个BeanDefinition.
    5. 所有类扫描完成后第一步即 将所有定义信息封装成了一个BeanDefinitionMap
  2. 从定义态到纯净态
    1. 实例化之前的验证,判断一个bean的prototype. 是否lazy, 是否abstract等。
    2. 只有一个bean是单例,非延迟加载,非抽象类。才会做实例化。
    3. 实例化的时候跟通过推断构造方法来实例化的。
    4. 实例化完成就是通过反射实例化了一个对象,并没有依赖注入。所以并不是一个完成的bean.
  3. 从纯净态到完成态
    1. spring处理合并后的beanDefinition.
    2. 判断是否需要完成属性注入。
    3. 如果需要完成属性注入,则开始注入。
    4. 判断bean的类型回调接口Aware接口。
    5. 调用声明周期回调方法。
    6. 如果需要代理则完成代理。
    7. put到单例池。

      spring 提供了哪些配置方式

  • 基于 xml 配置:bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签开头。例如:

    1. <bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
    2. <property name="name" value="Edureka"></property>
    3. </bean>
  • 基于注解配置:通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身,而不是使用 XML 来描述 bean 装配。默认情况下,Spring 容器中未打开注解装配。

    1. <beans>
    2. <context:annotation-config/>
    3. <!-- bean definitions go here -->
    4. </beans>
  • 基于 Java API 配置: Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。

    1. @Configuration
    2. public class StudentConfig {
    3. @Bean
    4. public StudentBean myStudent() {
    5. return new StudentBean();
    6. }
    7. }
  • 静态工厂配置 factory-method。 需要保证指定的方法时静态的。

  • 实例工厂配置 factory-bean 加 factory-method ,实际上就是@Bean注解。
  • factory-bean的方式。 一个bean实现implement FactoryBean, 通过getObjet来返回指定的bean.

    Spring 中的 bean 的作用域有哪些?

  1. singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
  2. prototype : 每次请求都会创建一个新的 bean 实例。
  3. request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
  4. session : :在一个HTTP Session中,一个Bean定义对应一个实例。该作用域仅在基于web的Spring

    什么是IOC

  5. 在没有spring之前

    1. Controller依赖Service,Service依赖Dao.
    2. 如果Service又依赖了其他实例,Controller实例化Service的方法也需要跟着变动。

image.png

  1. 在使用了工厂模式之后
    1. Controller不再实例化Service, Service的变动不再影响Controller对他的实例化,而是将所有Service的实例化交给了 工厂类,Controller从工厂类获取Service对象。

image.png

  1. 使用Spring之后

    1. 进一步解耦,Spring容器就是工厂类。
    2. 对象的创建,对象依赖的属性的注入,我们只需要通过xml注解等方式的配置。都交给spring管理。

      什么是IOC

  2. Inversion of control, 缩写IOC,控制反转的意思。

  3. 把对象的创建,对象之间依赖注入的过程,都交给spring管理。

    Spring怎么管理的

  4. xml配置方式

    1. xml文件配置
    2. spring启动时,扫描出xml配置的bean信息。反射创建对象。注入其他依赖的对象。
  5. 注解方式
    1. 需要交给spring管理的对象添加注解。
    2. 开启扫描指定包。
    3. spring启动时,扫描对应包的class文件。通过反射,根据注解找到需要管理的类。
  6. 默认都走无参构造。

    ApplicationContext类图关系

    image.png

DI

  1. Dependency Injection, 即依赖注入的意思。
  2. 程序员只需要将bean交给spring管理。不用再关心这些bean之间的依赖关系。添加 @Autowired 注解即可。
  3. 也就是说,一个bean对其他bean的依赖由spring进行注入。

    单例Bean的优势

  4. 减少了生词实例的性能消耗

    1. 反射和aop都会增加性能消耗。
    2. 重复生成bean,会重复分配内存。
  5. 减少jvm垃圾回收次数。
  6. 可以快速获取bean,单例bean除了第一次生成其余都是在内存中获取,所以很快。

    SpringBean是线程安全的吗

  7. 单例bean的情况

    1. 如果在类里面声明了成员变量,并且有读写操作(有状态),这个时候就会出现线程不安全。
    2. 如果单例bean没有成员变量,所有共享读写数据都是在方法入参上声明(无状态),此时没有线程安全问题 。
  8. 多实例每个实例一个线程,没有线程安全问题。

    Spring如何处理线程并发问题

  9. 设置为多实例 @Scope(“prototype”).

  10. 将成员变量放在ThreadLocal中,通过get set方法修改,获取。
  11. 通过同步锁的发方式解决。会影响服务器吞吐量。
  12. 单例,成员变量声明在方法上。

    什么是Bean的装配(注入),什么是Bean的自动装配(注入)

  13. 手动依赖注入。

  14. 自动依赖注入 @Autowired。

    自动注入有什么限制吗

  15. 一定要声明set方法。

  16. 重写, 可以通过 和 property可以覆盖。
  17. 基本数据类型不能自动注入。手动可以注入,如果使用@Value.
  18. 自动注入有可能匹配到多个。使用 @Autowried. 先根据类型,再根据名字。

    Bean有哪声明周期的回调方法?实现方式?

  19. 初始化

    1. @PostConstruct
    2. InitializingBean 重写 afterPropertiesSet方法
    3. 通过 initMethod,必须使用@Bean(InitMethod=””)或者使用xml。使用component不行。
  20. 销毁

    1. @PreDestroy
    2. DisposableBean 重写 destroy方法
    3. 通过 @Bean destroyMethod

      Spring 中的 bean 生命周期?

      Bean的声明周期是值Bean从创建到销毁的过程。
  21. 实例化

    1. 通过反射推断构造函数进行实例化。
    2. 实例工厂、静态工厂实例化
  22. 属性赋值
    1. 解析自动注入,DI的体现。
    2. 方式 @Autowarie 配置方式的 byname/bytype/constract/non等。
  23. 初始化
    1. 调用多个 Aware回调
      1. BeanNameAware-获取容器中的Bean名称
      2. BeanFactoryAware-获取当前BeanFactory。
      3. ApplicationContextAware 获取容器
      4. MessSoureAware 获取Message文本信息。
      5. ApplicationEventPublisherAware 发布时间
      6. ResourceLoadAware 获取资源文件。
    2. 调用初始化声明周期回调,上个题。
    3. 如果Bean实现了Aop,会创建动态代理。
  24. 销毁
    1. 在spring容器关闭的时候调用。
    2. 也会调用销毁的生命周期的回调。

      Spring是如何解决Bean的循环依赖的。

      什么是循环依赖

      Spring - 图5

      怎么解决的?

      采用三级缓存解决的,就是三个Map。
  • 一级缓存:存储完整的Bean.
  • 二级缓存:把三级缓存创建完成的放进去的B,或者AOP代理对象放入二级缓存。
  • 三级缓存:
    • 缓存的是函数接口:通过lambda把方法(Bean的实例和Bean的名字传递进去)。
    • 不会立即调用三级缓存。如果立即调用,不管bean是否循环依赖,都会在实例化后直接创建proxy,而正常的bean是在初始化的时候创建动态代理的。
    • ABA,A的第二次getBeanA 会调用三级缓存。
      • 如果A使用了AOP,创建动态代理对象。
      • 如果没有使用AOP,存储的就是放进去的A实例。
      • 然后保存在二级缓存中。避免重复创建。 如果不放 A被多个bean循环依赖。 二级缓存中就会有多个A被实例化。

Spring - 图6

二级缓存能不能解决循环依赖

  1. 如果只是死循环的问题,一级缓存就可以解决: 无法避免在并发情况下获取到不完整的bean的问题。
  2. 二级缓存必然也可以:但是如果A比多个对象循环依赖,A会被多次创建动态代理。

    多例bean能不能解决循环依赖。

  3. 不能,因为多例bean就没有使用缓存,1.2.3都没有用。

  4. 多例bean每次使用都需要重新创建,所有不适用缓存。不适用缓存保存早期对象。就无法解决循环依赖。
  5. 解决循环依赖的关键是有个缓存作为出口来换取该依赖对象。没有缓存就没有出口。

Spring有没有解决构造函数的循环依赖

  1. 默认没有解决,可以人工解决。
  2. 可以通过延迟加载来解决@Lazy.
  3. Lazy的原理: 不会立即调用实例化方法,只有在使用的时候才会生成对象。

    1. 当A依赖B, 创建A的时候,A的B属性实际上个cglib动态代理对象。 真正的B还是null.
    2. B依赖A也是。
    3. 调用A的 getB方法的时候,获取B的代理对象,调用 B代理的 getB方法才会创建B.

      Spring是如何帮助我们在并发的时候获取不完整的Bean.

      什么是不完整的Bean

      只完成了实例化,没有完成属性赋值。即没有DI.

      什么是并发获取

      多线程同时调用getBean方法。在一二三级缓存中获取对象问题。
      一个线程实例化完成、没有初始化完成。
      另一个线程直接从缓存中获取。

      怎么解决

  4. 双重检查锁。2个同步锁,2次检查一级缓存。

    @Compont @Controller @Respostitory @Service区别

    实际上其他几个都是Compont的原注解。
    只是为了可读性更好。

@Import可以有几种用法

  1. 直接指定类
    1. 如果是配置类按照配置类正常解析。
    2. 如果是个普通类就会解析成Ban.
  2. 通过ImportSelector可以一次性注册多个,返归一个String[] 数组,每个值就是一个完整的类路径。
    1. 通过DeferredImportSelector可以一次性注册多个,返回一个String[],每一个值就是类的完整路径。
  3. 通过ImportBeanDefintionRegistrar可以一次性注册多个,通过BeanDefinitionRegistry可以动态注册BeanDefintion。

    如何让自动注入没有找到依赖的Bean不报错

    @Autowrited(required=false)

    @Autowrited和@Resource区别

  4. Autowrited是Spring的注解,Resource是Jdk注解。

  5. Autowrite先根据类型找bean,再根据名称找bean。
  6. Resource先根据名称找bean,再根据类型找bean.

    AOP

    什么是AOP,能做什么

  7. 面向切面编程,将与业务无关的,却对多个对象产生影响的公共行为和逻辑,抽取并封装成一个可重用模块。

  8. 抽取并封装的模块被称为切面。
  9. 减少系统中的重复代码,降低模块之间的耦合度。
  10. 同时提高系统的可维护性。
  11. 可用于权限认证、日志、事物处理等。

    AOP常见的概念名词

  12. 切面 Aspect 指的就是就是切面类,类中管理 切点和通知。

  13. 连接点(Join Point)指的就是被增强的业务方法
  14. 通知(Advice): 就是需要增加到业务代码中的公共代码,通知有很多类型
    1. 前置通知
    2. 异常通知
    3. 后置通知
    4. 环绕通知
  15. 切入点(Ponitcut):有他决定哪些方法需要增强,哪些不需要增强,集合切点表达式。
  16. 目标对象 TargetObject: 指的就是被增强的对象。
  17. 织入 Weaving AspectJ独有

    AOP中有哪些通知

  18. 前置通知 Before : 在目标方法执行之前调用的通知功能。

  19. 后置通知 After: 在目标方法执行完成之后调用的的通知。相当于finally
  20. 返回通知 After-returning : 在目标方法执行之后调用的通知。
  21. 异常通知 after-throwing: 在目标方法抛出异常之后调用的通知。
  22. 环绕通知 Around: 通知包裹了被通知的方法,之前和之后自定义执行。
  • 执行顺序
    • 5.2.7之前:
      • 正常: Before ——> 方法 ——> after——> afterreturning .
      • 异常: Before——->方法——> after ——> afterThrowiing.
    • 5.2.7之后:
      • 正常: Before ——> 方法 ——> afterreturning ——> after.
      • 异常: Before——->方法——> afterThrowiing ——> after.

        SpringAop和AspectJ AOP有什么区别

  1. 当在Spring中使用@Aspect,@Before 等这些注解的时候就需要添加AspectJ依赖。
  2. SpringAop提供的AspectJ的支持,但是只用到了AspectJ的切点解析和匹配。
  3. SpringAop基于动态代理来实现,默认的如果使用接口,用JDK提供的动态代理实现。如果么有接口,使用CGLib实现。
  4. Aspectj是静态代理的增强,就是在编译时会生成AOP代理类。

    JDK动态代理实现

  5. 接口类 ```java package proxy;

public interface Star { String sing(String name);

String dance(String name);

}


2. 被代理类实现接口
```java
package proxy;

public class LiuDeHua implements Star
{   
    @Override
    public String sing(String name)
    {
         System.out.println("给我一杯忘情水");

        return "唱完" ;
    }

    @Override
    public String dance(String name)
    {
        System.out.println("开心的马骝");

        return "跳完" ;
    }
}
  1. 实现InvocationHander接口的包装了,这个仅仅是个wapper,不是代理类。 ```java package proxy;

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;

public class StarProxy implements InvocationHandler { // 目标类,也就是被代理对象 private Object target;

public void setTarget(Object target)
{
    this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
    // 这里可以做增强
    System.out.println("收钱");

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

    return result;
}

// 生成代理类
public Object CreatProxyedObj()
{
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}  

}

<a name="vteaf"></a>
### cglib动态代理实现
```java
package proxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor
{
    // 根据一个类型产生代理类,此方法不要求一定放在MethodInterceptor中
    public Object CreatProxyedObj(Class<?> clazz)
    {
        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(clazz);

        enhancer.setCallback(this);

        return enhancer.create();
    }

    @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable
    {
        // 这里增强
        System.out.println("收钱");

        return arg3.invokeSuper(arg0, arg2);
    } 
}

第一个参数传递的是this,代表代理类本身,第二个参数标示拦截的方法,第三个参数是入参,第四个参数是cglib方法,intercept方法完成增强后,我们调用cglib方法间接调用父类方法完成整个方法链的调用。

JDK动态代理和CGLib动态代理的区别

  1. JDK动态代理只提供接口的代理,不支持类的代理。
    1. JDK会在运行时生成一个动态代理代,$proxy*.class.
    2. 该类是实现了目标类的一个接口,并且会实现接口所有方法的增强代码。
    3. 调用时先去调用处理类进行增强,再通过反射的方式进行调用目标方法。
  2. 代理类如果没有实现接口,那么SpringAOP会选择使用CGLIB来动态代理目标类。
    1. 主要实现时继承后重写父类方法。
    2. 调用时先通过代理类增强,再直接调用父类方法。
  • CGLIB是通过继承的方式做的动态代理。因此一个类如果被标记为final,那么是无法使用CGLIB做动态代理的。
  1. 创建对象速度:jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码
  2. 方法调用速度:Jdk是反射调用,调用比cglib直接调用父类慢。
  3. 内存消耗:另外由于CGLIB的大部分类是直接对Java字节码进行操作,这样生成的类会在Java的永久堆中。如果动态代理操作过多,容易造成永久堆满,触发OutOfMemory异常。

    JavaConfig的方式如何开启AOP,如何强制使用cglib。

  4. 配置类需要开启配置 EnableAspectJAutoProxy.

  5. 如果需要强制使用cglib,需要配置 proxyTargetClass=true.
  6. 在线程中暴露代理对象 , exposeProxy=true.

    AOP失效原因,怎么解决。

  7. 方法不是private. 解决 改为public

  8. 目标类没有配置为springBean. 解决:配置为SpringBean.
  9. 切点表达式没有配置正确。
  10. 在本类内部调用不会走代理。

    1. 解决方式一:在本类注入当前类对象,实际上注入的就是代理对象。
    2. 解决方式二:
      1. 在配置类中开启暴露代理对象 exposeProxy=true
      2. 内部调用使用 AopContext.currentProxy()再调用目标方法。

        Spring事物

        Spring支持的事物管理类型

  11. 编程式事物,通过编程的方式管理事物,灵活性高,难维护。

  12. 声明式事物,通过注解方式管理事物。业务代码和事物管理分离。

    Spring事物实现的方式有哪些

  13. 声明式

  14. 编程式: 直接使用 TransactionTemplate 的 execute
    1. PlatformTransactionManager :Spring并不直接管理事务,

通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,也就是将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现
image.png
b. TransactionStatus :在上面 PlatformTransactionManager 接口中,有如下方法:
image.png
这个方法返回的是 TransactionStatus对象,然后程序根据返回的对象来获取事务状态,然后进行相应的操作。
而 TransactionStatus 这个接口的内容如下:
image.png
c. TransactionDefinition 事务定义
d. 一般使用直接 使用 TransactionTemplate.excute执行。

package com.thit.serviceImpl;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.thit.dao.OrderDao;
import com.thit.dao.ProductDao;
import com.thit.entity.Order;
import com.thit.entity.Product;
import com.thit.service.OrderService;
@Service(value="orderServiceimpl2")
public class OrderServiceImpl2 implements OrderService {
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private ProductDao productDao;
    @Autowired
    private TransactionTemplate template;

    public void addOrder(final Order order) {
        // TODO Auto-generated method stub
        //订单表
        System.out.println("进入");
        order.setCreateTime(new Date());
        order.setStatus("待付款测试2");
        template.execute(new TransactionCallback<Object>() {

            public Object doInTransaction(TransactionStatus status) {
                // TODO Auto-generated method stub
                 //开启事务
                try {
                     orderDao.insert(order);
                     //商品
                     Product p=productDao.select(order.getProductsId());
                     p.setStock(p.getStock()-order.getNumber());
                     productDao.update(p);


                } catch (Exception e) {
                    // TODO: handle exception
                    //回滚
                    status.setRollbackOnly();
                    e.printStackTrace();
                }
                return null;
            }
        });



    }

}

Spring事物的传播行为

事物的传播行为指的是当开启当前事物时,如果外部有事物,如何处理。
常用的三种:

  1. Required 默认的,外部不存在事物,开启新事物。存在融入到外部事物中。默认的。适用场景为增删改操作。
  2. Support 外部不存在事物,不开启新事物,外部存在,融入到外部。适用查询操作。
  3. Require_new, 外部不存在事物,开启新事物,外部存在,不使用外部事物。 适用内部与外部事物 业务没有管理的场景。

    事物的隔离级别

  4. Isolation.DEFAULT:为数据源的默认隔离级别

  5. isolation=Isolation.READ_UNCOMMITTED:读未提交 不能防止脏、不可、幻读
  6. iIsolation.READ_COMMITTED:授权读取级别 可以防止脏读、不能防止不可、幻读
  7. iIsolation.REPEATABLE_READ:可重复读取级别, 可以防止脏读、不可重复读,不能防止幻读。
  8. iIsolation.SERIALIZABLE:序列化级别 可以防止脏、不可、幻读。

Spring中事物失效原因

  • 同AOP失效原因。
  1. private
  2. 没有配置为bean
  3. 内部调用

    Spring中使用了哪些设计模式

  4. 简单工程 BeanFactory.

  5. 工厂方法 FactoryBean.
  6. 单例模式 Bean实例
  7. 适配器模式 SpringMVC中的HandlerAdatper.
  8. 装饰器模式 BeanWapper.
  9. 代理模式 AOP底层
  10. 观察者模式,Spring时间监听。
  11. 策略模式 excudeFilters、includeFilters.
  12. 模板方法模式
  13. 责任链模式 -AOP中的方法调用

SpringMVC

常用注解

@Configuration

  1. 声明这是一个spring配置类,spring的注解。不是boot的。
  2. 配置类里面使用@Bean注解标注在方法上,给容器注册组件。默认单实例
  3. 配置类本身也是组件。
  4. 参数 proxyBeanMethods : 代理@Bean方法
    1. 默认是true,默认就是全量模式,表示@Bean所标注的bean,每次创建先去容器看有没有,没有才创建。
    2. false,轻量模式,调用方法直接new. 不走代理,也不去容器看有没有。
    3. 选择: 配置组件之间无依赖,建议使用lite轻量模式,加速容器启动过程,减少判断。如果配置组件之间有依赖关系,即必须是单例的场景下,使用Full模式。

      @Import

      导入某个类,即创建某个类的实例,spring的注解,不是boot的

      @Conditional

      条件判断,在某些场景下,开启配置。或者不开启。

      @ImportResource

      原生配置文件导入。

      @ConfigurationProperties + @EnableConfigurationProperties

      属性值绑定并加载到容器

      @ConfigurationProperties + @Component

      同上

      拦截器、过滤器区别

      过滤器

      什么是过滤器

      1. 过滤器的英文名称为 Filter, 是 Servlet 技术中最实用的技术。
      2. 如同它的名字一样,过滤器是处于客户端和服务器资源文件之间的一道过滤网,帮助我们过滤掉一些不符合要求的请求,通常用作 Session 校验,判断用户权限,如果不符合设定条件,则会被拦截到特殊的地址或者基于特殊的响应。

过滤器的使用

首先需要实现 Filter接口然后重写它的三个方法
init 方法:在容器中创建当前过滤器的时候自动调用
destory 方法:在容器中销毁当前过滤器的时候自动调用
doFilter 方法:过滤的具体操作

代码示例

import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;

@Log4j2
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("初始化过滤器");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper((HttpServletResponse) response);
        String requestUri = request.getRequestURI();
        log.info("请求地址是:"+requestUri);
        if (requestUri.contains("/addSession")
            || requestUri.contains("/removeSession")
            || requestUri.contains("/online")
            || requestUri.contains("/favicon.ico")) {
            filterChain.doFilter(servletRequest, response);
        } else {
            wrapper.sendRedirect("/online");
        }
    }

    @Override
    public void destroy() {
        //在服务关闭时销毁
        log.info("销毁过滤器");
    }
}

拦截器

什么是拦截器

  1. Java中的拦截器是动态拦截 action 调用的对象,然后提供了可以在 action 执行前后增加一些操作,也可以在 action 执行前停止操作,功能与过滤器类似,但是标准和实现方式不同。
  2. 登录认证:在一些应用中,可能会通过拦截器来验证用户的登录状态,如果没有登录或者登录失败,就会给用户一个友好的提示或者返回登录页面,当然大型项目中都不采用这种方式,都是调单点登录系统接口来验证用户。
  3. 记录系统日志:我们在常见应用中,通常要记录用户的请求信息,比如请求

ip,方法执行时间等,通过这些记录可以监控系统的状况,以便于对系统进行信息监控、信息统计、计算 PV、性能调优等。

  1. 通用处理:在应用程序中可能存在所有方法都要返回的信息,这是可以利用拦截器来实现,省去每个方法冗余重复的代码实现。

拦截器的使用

我们需要实现 HandlerInterceptor 类,并且重写三个方法:

preHandle:在 Controller 处理请求之前被调用,返回值是 boolean类型,如果是true就进行下一步操作;若返回false,则证明不符合拦截条件,在失败的时候不会包含任何响应,此时需要调用对应的response返回对应响应。

postHandler:在 Controller 处理请求执行完成后、生成视图前执行,可以通过ModelAndView对视图进行处理,当然ModelAndView也可以设置为 null。

afterCompletion:在 DispatcherServlet 完全处理请求后被调用,通常用于记录消耗时间,也可以对一些资源进行处理。

代码示例

@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("【MyInterceptor】调用了:{}", request.getRequestURI());
        request.setAttribute("requestTime", System.currentTimeMillis());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) throws Exception {
        if (!request.getRequestURI().contains("/online")) {
            HttpSession session = request.getSession();
            String sessionName = (String) session.getAttribute("name");
            if ("cj".equals(sessionName)) {
                log.info("【MyInterceptor】当前浏览器存在 session:{}",sessionName);
            }
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        long duration = (System.currentTimeMillis() - (Long)request.getAttribute("requestTime"));
        log.info("【MyInterceptor】[{}]调用耗时:{}ms",request.getRequestURI(), duration);
    }
}

拦截区过滤器区别

1、拦截器是基于java的反射机制的 - - - - - 过滤器是基于函数回调
2、拦截器不依赖与servlet容器 - - - - - 过滤器依赖与servlet容器,
3、拦截器只能对action请求起作用 - - - - - 过滤器则可以对几乎所有的请求起作用
4、拦截器可以访问action上下文、值栈里的对象 - - - - - 过滤器不能
5、在action的生命周期中,拦截器可以多次被调用 - - - - - 过滤器只能在容器初始化时被调用一次

SpirngBoot的理解,有哪些优点

Spring是用来快速开发spring应用程序的脚手架。目的是简化spring配置和开发过程。

  1. 提供了很多内置starter结合自动配置。对主流框架无配置继承,开箱即用。
  2. 简化了开发,可以做到0xml配置。
  3. 内置web容器。
  4. 管理了三方依赖版本。减少冲突。
  5. 自带监控功能,可监控运行情况,内存,线层池,http等装填。

    SPirng 和SpringBoot的关系区别。

  6. SpringFramework是一个容器框架

  7. SpringBoot不是框架,他是一个可以快速构建spring的脚手架。

    SpringBoot核心注解。

  8. SpringBootApplication 标记当前应用为SpringBoot项目。

  9. SpringBootApplication 实际上是三个注解的组合注解: 包括 ComponentScan 、SpringBootConfigration、EnableAutoConfigration.

    1. 其中 第一个注解SpringBootConfigration 使用了注解@Configration 。表明了当前类是个配置类。
    2. 第二个注解 ComponentScan 表示开启扫描。
    3. 第三个注解 EnableAutoConfigRation. 这个注解包含了两个注解
      1. AutoConfigrationPacakge —> Import Registrar.class}
      2. @Import({AutoConfigurationImportSelector.class})
        1. 自定义start能生效就是因为整个地方的存在。
        2. 他会扫描容器里面所有META-INF/spring.factories里面的文件

          自定义Starter

  10. 自定义starter中 META-INF文件夹下创建文件 spring-factories。并指定配置类。

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\配置类全类名
    
  11. 自动类上可以通过 Conditonal配置相关条件。

    SpringBoot配置文件加载顺序。

  12. 通过ConfigFileApplicationListener读取。

  13. 优先级高到第。

    1. file: ./config 当前jar包的config文件夹。
    2. file下的文件 同config同级文件。
    3. calsspath:config
    4. classpath:

      SpringCloud

      Eureka

      什么是Eureka

      Eureka作为SpringCloud的服务注册功能服务器,他是服务注册中心,系统中的其他服务使用Eureka的客户端将其连接到Eureka Service中,并且保持心跳,这样工作人员可以通过EurekaService来监控各个微服务是否运行正常。

      Eureka怎么实现高可用

      注册多台 Eureka ,然后把 SpringCloud 服务互相注册,客户端从 Eureka 获取信息时,按照Eureka 的顺序来访问。

      什么是Eureka的自我保护模式

      默认情况下,如果 Eureka Service 在一定时间内没有接收到某个微服务的心跳, Eureka Service 会进入自我保护模式,在该模式下Eureka Service 会保护服务注册表中的信息,不在删除注册表中的数据,当网络故障恢复后,Eureka Servic 节点会自动退出自我保护模式

      DiscoveryClient的作用

      可以从注册中心中根据服务别名获取注册的服务器信息。

      Eureka和ZooKeeper都可以提供服务注册与发现的功能,请说说两个的区别

  14. ZooKeeper中的节点服务挂了就要选举 在选举期间注册服务瘫痪,虽然服务最终会恢复,但是选举期间不可用的, 选举就是改微服务做了集群,必须有一台主其他的都是从

  15. Eureka各个节点是平等关系,服务器挂了没关系,只要有一台Eureka就可以保证服务可用,数据都是最新的。 如果查询到的数据并不是最新的,就是因为Eureka的自我保护模式导致的
  16. Eureka本质上是一个工程,而ZooKeeper只是一个进程
  17. Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像ZooKeeper 一样使得整个注册系统瘫痪
  18. ZooKeeper保证的是CP,Eureka保证的是AP

    CloudGateWay

    什么是网关?

    网关相当于一个网络服务架构的入口,所有网络请求必须通过网关转发到具体的服务

    网关的作用是什么

    统一管理微服务请求,权限控制、负载均衡、路由转发、监控、安全控制黑名单和白名单等

    网关与过滤器有什么区别

    网关是对所有服务的请求进行分析过滤,过滤器是对单个服务而言。

    Ribbon

    Ribbon是什么

    Ribbon客户端组件提供一系列完善的配置项,如连接超时,重试等。简单的说,就是在配置文件中列出后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。(有点类似Nginx)

    Ribbon底层实现原理

    Ribbon 使用 discoveryClient 从注册中心读取目标服务信息,对同一接口请求进行计数,使用 % 取余算法获取目标服务集群索引,返回获取到的目标服务信息。

@LoadBalanced注解的作用

开启客户端负载均衡。

Hystrix

什么是断路器

当一个服务调用另一个服务由于网络原因或自身原因出现问题,调用者就会等待被调用者的响应 当更多的服务请求到这些资源导致更多的请求等待,发生连锁效应(雪崩效应)

断路器有三种状态

打开状态:一段时间内 达到一定的次数无法调用 并且多次监测没有恢复的迹象 断路器完全打开 那么下次请求就不会请求到该服务 半开状态:短时间内 有恢复迹象 断路器会将部分请求发给该服务,正常调用时 断路器关闭 关闭状态:当服务一直处于正常状态 能正常调用

什么是 Hystrix

雪崩效应是在大型互联网项目中,当某个服务发生宕机时,调用这个服务的其他服务也会发生宕机,大型项目的微服务之间的调用是互通的,这样就会将服务的不可用逐步扩大到各个其他服务中,从而使整个项目的服务宕机崩溃.发生雪崩效应的原因有以下几点

单个服务的代码存在bug. 2请求访问量激增导致服务发生崩溃(如大型商城的枪红包,秒杀功能). 3.服务器的硬件故障也会导致部分服务不可用.

服务雪崩效应产生的原因

因为Tomcat默认情况下只有一个线程池来维护客户端发送的所有的请求,这时候某一接口在某一时刻被大量访问就会占据tomcat线程池中的所有线程,其他请求处于等待状态,无法连接到服务接口。

谈谈服务降级、熔断、服务隔离

  • 服务降级:当客户端请求服务器端的时候,防止客户端一直等待,不会处理业务逻辑代码,直接返回一个友好的提示给客户端。

  • 服务熔断是在服务降级的基础上更直接的一种保护方式,当在一个统计时间范围内的请求失败数量达到设定值(requestVolumeThreshold)或当前的请求错误率达到设定的错误率阈值(errorThresholdPercentage)时开启断路,之后的请求直接走fallback方法,在设定时间(sleepWindowInMilliseconds)后尝试恢复。

  • 服务隔离就是Hystrix为隔离的服务开启一个独立的线程池,这样在高并发的情况下不会影响其他服务。服务隔离有线程池和信号量两种实现方式,一般使用线程池方式。

    服务降级底层是如何实现的

  • Hystrix实现服务降级的功能是通过重写HystrixCommand中的getFallback()方法,当Hystrix的run方法或construct执行发生错误时转而执行getFallback()方法。

    Feign

    什么是Feign

  • Feign 是一个声明web服务客户端,这使得编写web服务客户端更容易

  • 他将我们需要调用的服务方法定义成抽象方法保存在本地就可以了,不需要自己构建Http请求了,直接调用接口就行了,不过要注意,调用方法要和本地抽象方法的签名完全一致。

    SpringCloud有几种调用接口方式

  • Feign

  • RestTemplate

    Ribbon和Feign调用服务的区别

    调用方式同:Ribbon需要我们自己构建Http请求,模拟Http请求然后通过RestTemplate发给其他服务,步骤相当繁琐

而Feign则是在Ribbon的基础上进行了一次改进,采用接口的形式,将我们需要调用的服务方法定义成抽象方法保存在本地就可以了,不需要自己构建Http请求了,直接调用接口就行了,不过要注意,调用方法要和本地抽象方法的签名完全一致。

Bus

什么是 Spring Cloud Bus?

Spring Cloud Bus就像一个分布式执行器,用于扩展的Spring Boot应用程序的配置文件,但也可以用作应用程序之间的通信通道。
Spring Cloud Bus 不能单独完成通信,需要配合MQ支持
Spring Cloud Bus一般是配合Spring Cloud Config做配置中心的
Springcloud config实时刷新也必须采用SpringCloud Bus消息总线

Config

什么是Spring Cloud Config?

Spring Cloud Config为分布式系统中的外部配置提供服务器和客户端支持,可以方便的对微服务各个环境下的配置进行集中式管理。Spring Cloud Config分为Config Server和Config Client两部分。Config Server负责读取配置文件,并且暴露Http API接口,Config Client通过调用Config Server的接口来读取配置文件。
[

](https://blog.csdn.net/weixin_43122090/article/details/105463548)