解决POST、GET请求中文乱码问题

  • 解决post请求乱码问题: 在web.xml中配置一个CharacterEncodingFilter过滤器,设置成 utf-8;
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
@RequestMapping(value  = "/add", produces = "text/plain;charset=utf-8")
  • get 请求中文参数出现乱码解决方法有两个

    • 修改 tomcat 配置文件添加编码与工程编码一致,如下:
    <ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/
    • 另外一种方法对参数进行重新编码
    //ISO8859-1 是 tomcat 默认编码,需要将 tomcat 编码后的内容按 utf-8 编码
    String userName = new String(request.getParamter(“userName”).getBytes(“ISO8859-1”),“utf-8”)

Redis

Redis作用
  1. 内存存储、持久化,放在内存中,断电即失(持久化重要(RDB、AOF))
  2. 效率高,可以用于告诉缓存
  3. 发布订阅系统
  4. 地图信息分析
  5. 计数器、计数器(浏览量)
特性
  1. 多样的数据类型
  2. 持久化
  3. 集群
  4. 事务
基础知识
  • redis默认16个数据库,默认使用第0个,可以使用select进行切换数据库
  • 常用命令

    #查看数据库大小
    DBSIZE
    
    #查看所有的key
    KEY *
    
    #清空当前数据库
    flushdb
    
    #清空所有数据库
    flushall
Redis是单线程的

Redis是基于内存操作,所以他的瓶颈在于机器的内存和网络带宽

SpringBean的配置详解

Bean的实例化配置

  • 静态工厂方法实例化Bean
  • 实例工厂方法实例化Bean
  • 实现FactoryBean规范延迟实例化Bean

Bean的依赖注入配置

依赖注入的两种方式
  1. 通过Bean的set方法注入

  2. 通过构造Bean的方法注入

ref用于引用其他的Bean的id;value用于注入普通属性值.

依赖注入的数据类型有如下三种:
  • 普通数据类型,例如:String,int,boolean等,通过value属性指定
  • 引用数据类型,例如:UserDaoImpl,DataSource等,通过ref属性指定
  • 集合数据类型,例如:List,Map,Properties等

Spring 声明式事务无效可能的原因有哪些?

答:可能的原因如下:

  • MySQL 使用的是 MyISAM 引擎,而 MyISAM 是不支持事务的;
  • @Transactional 使用在非 public 方法上,@Transactional 注解只能支持 public 级别,其他类型声明的事务不会生效;
  • @Transactional 在同一个类中无事务方法 A() 内部调用有事务方法 B(),那么此时 B() 事物不会生效。Spring 中的 AOP 的底层实现原理是什么?

答:Spring AOP 的底层实现原理就是动态代理。Spring AOP 的动态代理有两种实现方式,对于接口使用的是 JDK 自带的动态代理来实现的,而对比非接口使用的是 CGLib 来实现的。

Spring 中 Bean 的生命周期

答:Spring 中 Bean 的生命周期如下:

  • ① 实例化 Bean:对于 BeanFactory 容器,当客户向容器请求一个尚未初始化的 Bean 时,或初始化 Bean 的时候需要注入另一个尚未初始化的依赖时,容器就会调用 createBean 进行实例化。对于 ApplicationContext 容器,当容器启动结束后,通过获取 BeanDefinition 对象中的信息,实例化所有的 Bean;
  • ② 设置对象属性(依赖注入):实例化后的对象被封装在 BeanWrapper 对象中,紧接着 Spring 根据 BeanDefinition 中的信息以及通过 BeanWrapper 提供的设置属性的接口完成依赖注入;
  • ③ 处理 Aware 接口:Spring 会检测该对象是否实现了 xxxAware 接口,并将相关的 xxxAware 实例注入给 Bean:
  • 如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String BeanId) 方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值;
  • 如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory() 方法,传递的是 Spring 工厂自身;
  • 如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用 setApplicationContext(ApplicationContext) 方法,传入 Spring 上下文;
  • ④ BeanPostProcessor:如果想对 Bean 进行一些自定义的处理,那么可以让 Bean 实现了 BeanPostProcessor 接口,那将会调用 postProcessBeforeInitialization(Object obj, String s) 方法;
  • ⑤ InitializingBean 与 init-method:如果 Bean 在 Spring 配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法;
  • ⑥ 如果这个 Bean 实现了 BeanPostProcessor 接口,将会调用 postProcessAfterInitialization(Object obj, String s) 方法;由于这个方法是在 Bean 初始化结束时调用的,因而可以被应用于内存或缓存技术;

以上几个步骤完成后,Bean 就已经被正确创建了,之后就可以使用这个 Bean 了。

  • ⑦ DisposableBean:当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用其实现的 destroy() 方法;
  • ⑧ destroy-method:最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。

Spring 中都是用到的设计模式

答:Spring 中使用的设计模式如下:

  • 工厂模式:通过 BeanFactory、ApplicationContext 来创建 bean 都是属于工厂模式;
  • 单例、原型模式:创建 bean 对象设置作用域时,就可以声明 Singleton(单例模式)、Prototype(原型模式);
  • 察者模式:Spring 可以定义一下监听,如 ApplicationListener 当某个动作触发时就会发出通知;
  • 责任链模式:AOP 拦截器的执行;
  • 策略模式:在创建代理类时,如果代理的是接口使用的是 JDK 自身的动态代理,如果不是接口使用的是 CGLIB 实现动态代理。

设置 Ehcache 为 MyBatis 的二级缓存

直接在 XML 中配置开启 EhcacheCache

<mapper namespace="com.interview.repository.ClassesReposirory"> 
    <!-- 开启二级缓存 -->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache" >
        <!-- 缓存创建以后,最后一次访问缓存的时间至失效的时间间隔 -->
        <property name="timeToIdleSeconds" value="3600"/>
        <!-- 缓存自创建时间起至失效的时间间隔-->
        <property name="timeToLiveSeconds" value="3600"/>
        <!-- 缓存回收策略,LRU 移除近期最少使用的对象 -->
        <property name="memoryStoreEvictionPolicy" value="LRU"/>
    </cache>

    <select id="findById" parameterType="java.lang.Long" resultType="com.interview.entity.Classes">
        select * from classes where id = #{id}
    </select>
</mapper>

反射的基本使用

下来我们通过反射调用类中的某个方法,来学习反射的基本使用。

使用反射调用类中的方法,分为三种情况:

  • 调用静态方法
  • 调用公共方法
  • 调用私有方法

假设有一个实体类 MyReflect 包含了以上三种方法,代码如下:

package com.interview.chapter4;
class MyReflect {
    // 静态方法
    public static void staticMd() {
        System.out.println("Static Method");
    }
    // 公共方法
    public void publicMd() {
        System.out.println("Public Method");
    }
    // 私有方法
    private void privateMd() {
        System.out.println("Private Method");
    }
}

下面分别来看,使用反射如何调用以上三种类型的方法。

反射调用静态方法
Class myClass = Class.forName("com.interview.chapter4.MyReflect");
Method method = myClass.getMethod("staticMd");
method.invoke(myClass);
反射调用公共方法
Class myClass = Class.forName("com.interview.chapter4.MyReflect");
// 创建实例对象(相当于 new )
Object instance = myClass.newInstance();
Method method2 = myClass.getMethod("publicMd");
method2.invoke(instance);
反射调用私有方法
Class myClass = Class.forName("com.interview.chapter4.MyReflect");
// 创建实例对象(相当于 new )
Object object = myClass.newInstance();
Method method3 = myClass.getDeclaredMethod("privateMd");
method3.setAccessible(true);
method3.invoke(object);

反射使用总结

反射获取调用类可以通过 Class.forName(),反射获取类实例要通过 newInstance(),相当于 new 一个新对象,反射获取方法要通过 getMethod(),获取到类方法之后使用 invoke() 对类方法进行调用。如果是类方法为私有方法的话,则需要通过 setAccessible(true) 来修改方法的访问限制,以上的这些操作就是反射的基本使用。