【第二章:Java核心技术解析】第14节:Java框架 - Spring必会知识点
大家好,很高兴我们可以继续学习交流Java高频面试题。本小节主要交流学习Spring框架的相关知识点。Spring是目前流行的一站式框架,包括SpringMVC和SpringBoot都给我们搭建Web系统提供了便利。
做为一名Java开发工程师,在日常的工作中,我们必不可少的会使用到Spring框架。有的同学对Spring的使用比较熟练,但是对其技术原理却不甚了解,而这正是面试中所需要具备的能力。接下来,让我们一起来交流学习Spring相关的技术原理吧~
(1)说一下Spring中的控制反转(IOC)吧。
答:IOC也叫控制反转,将对象间的依赖关系交给Spring容器,使用配置文件来创建所依赖的对象,由主动创建对象改为了被动方式,实现解耦合。可以通过注解@Autowired和@Resource来注入对象,被注入的对象必须被下边的四个注解之一标注:
- @Controller
- @Service
- @Repository
- @Component
在Spring配置文件中配置 <context:annotation-config/>元素开启注解。还有一个概念是DI(依赖注入),和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖IOC容器来动态注入对象需要的外部资源(对象等)。
解析:
Spring是一个轻量级的IOC和AOP容器框架。是为Java应用程序提供基础服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。
Spring的核心模块如下所示:
- Spring Core:是核心类库,提供IOC服务;
- Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
- Spring AOP:提供AOP服务;
- Spring DAO:对JDBC进行了抽象,简化了数据访问异常等处理;
- Spring ORM:对现有的ORM持久层框架进行了支持;
- Spring Web:提供了基本的面向Web的综合特性;
- Spring MVC:提供面向Web应用的Model-View-Controller实现。
Spring的优点有哪些呢?
- Spring的依赖注入将对象之间的依赖关系交给了框架来处理,减小了各个组件之间的耦合性;
- AOP面向切面编程,可以将通用的任务抽取出来,复用性更高;
- Spring对于其余主流框架都提供了很好的支持,代码的侵入性很低。
简单阐述了Spring框架,并且介绍了其关键技术IOC之后,我们一起来看看Spring的另一个关键技术AOP(面向切面编程)吧~
(2)Spring中的AOP面向切面编程有了解吗?
答: AOP,面向切面编程是指当需要在某一个方法之前或者之后做一些额外的操作,比如说日志记录,权限判断,异常统计等,可以利用AOP将功能代码从业务逻辑代码中分离出来。
AOP中有如下的操作术语:
- Joinpoint(连接点): 类里面可以被增强的方法,这些方法称为连接点
- Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
- Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
- Aspect(切面):是切入点和通知(引介)的结合
- Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或属性
- Target(目标对象):代(dai)理的目标对象(要增强的类)
- Weaving(织入):是把增强应用到目标的过程,把advice 应用到 target的过程
- Proxy(代(dai)理):一个类被AOP织入增强后,就产生一个结果代(dai)理类
我们来简单理解下重要概念。切入点就是在类里边可以有很多方法被增强,比如实际操作中,只是增强了个别方法,则定义实际被增强的某个方法为切入点;通知/增强 就是指增强的逻辑,比如扩展日志功能,这个日志功能称为增强;切面就是把增强应用到具体方法上面的过程称为切面。
Spring中的AOP主要有两种实现方式:
- 使用JDK动态代(dai)理实现,使用java.lang.reflection.Proxy类来处理
- 使用cglib来实现
两种实现方式的不同之处:
JDK动态代(dai)理,只能对实现了接口的类生成代(dai)理,而不是针对类,该目标类型实现的接口都将被代(dai)理。原理是通过在运行期间创建一个接口的实现类来完成对目标对象的代(dai)理。实现步骤大概如下:
- 定义一个实现接口InvocationHandler的类
- 通过构造函数,注入被代(dai)理类
- 实现invoke( Object proxy, Method method, Object[ ] args)方法
- 在主函数中获得被代(dai)理类的类加载器
- 使用Proxy.newProxyInstance( )产生一个代(dai)理对象
- 通过代(dai)理对象调用各种方法
cglib主要针对类实现代(dai)理,对是否实现接口无要求。原理是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以被代(dai)理的类或方法不可以声明为final类型。实现步骤大概如下:
- 定义一个实现了MethodInterceptor接口的类
- 实现其 intercept()方法,在其中调用proxy.invokeSuper( )
接下来,我们看分别给出JDK动态代(dai)理和cglib实现动态代(dai)理的Demo。
JDK动态代(dai)理Demo:
package com.package1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy { public static void main(String[] args){ //定义一个people作为被代(dai)理的实例 IPeople ple=new People(); //定义一个handler InvocationHandler handle=new MyHandle(ple); //获得类加载器 ClassLoader cl=ple.getClass().getClassLoader(); //动态产生一个代(dai)理,下边两种方法均可 // IPeople p=(IPeople) Proxy.newProxyInstance(cl, new Class[]{IPeople.class}, handle); IPeople p=(IPeople) Proxy.newProxyInstance(cl, ple.getClass().getInterfaces(), handle); //执行被代(dai)理者的方法。 p.func(); } } class MyHandle implements InvocationHandler{ //被代(dai)理的实例 Object obj=null; //我要代(dai)理谁 public MyHandle(Object obj){ this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result=method.invoke(this.obj, args); return result; } } interface IPeople{ public void fun(); public void func(); } //实际被代(dai)理的类 class People implements IPeople{ @Override public void fun() { System.out.println("这是fun方法"); } @Override public void func() { System.out.println("这是func方法"); } }
cglib实现动态代(dai)理Demo:
package com.pak; import net.sf.cglib.proxy.*; import java.lang.reflect.Method; public class TestCglib { public static void main(String[] args) { // 定义一个回调接口的数组 Callback[] callbacks = new Callback[] { new MyApiInterceptor(), new MyApiInterceptorForPlay() }; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Person.class); // 设置要代(dai)理的父类 enhancer.setCallbacks(callbacks); // 设置回调的拦(lan)截器数组 enhancer.setCallbackFilter(new CallbackFilterImpl()); // 设置回调选择器 Person person = (Person) enhancer.create(); // 创建代(dai)理对象 person.eat(); System.out.println("--------------------"); person.play(); } } class MyApiInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("吃饭前我会先洗手"); // 此处可以做一些操作 Object result = proxy.invokeSuper(obj, args); System.out.println("吃完饭我会先休息会儿" ); // 方法调用之后也可以进行一些操作
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
<p> Java开发岗高频面试题全解析,专刊正文共计31节,已经全部更新完毕。专刊分9个模块来对Java岗位面试中的知识点进行解析,包括通用面试技能,Java基础,Java进阶,网络协议,常见框架以及算法,设计模式等。专刊串点成面的解析每个面试题背后的技术原理,由浅入深,循序渐进,力争让大家掌握面试题目的背后的技术原理,摒弃背题模式的陋习。 专刊详细信息,请查阅专刊大纲和开篇词的介绍。 本专刊购买后即可解锁所有章节,故不可以退换哦~ </p> <p> <br /> </p>