Java面试知识点(全)
导航: https://nanxiang.blog.csdn.net/article/details/130640392
注:随时更新
Spring原理
Spring ioc概念:控制权由对象本身转向容器;由容器根据配置文件去创建实例并创建各个实例之间的依赖关系。核心:beanFactory;在Spring中,beanFactory创建的各个实例称作bean,其通过java反射实现
Spring还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象 进行监督和控制(指定类或者通用)从而达到对一个模块扩充的功能。这些都是通过配置类达到的。AOP其实现的原理为动态代理(面向接口使用JDK的,面向类使用cglib),
Spring目的:就是让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过配置类说明管理的(Spring根据这些配置 内部通过反射去动态的组装对象)
要记住:Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能。
Spring里用的最经典的一个设计模式就是:模板方法模式。(这里我都不介绍了,是一个很常用的设计模式),Spring里的配置是很多的,很难都记住,但是Spring里的精华也无非就是以上的两点,把以上两点跟理解了 也就基本上掌握了Spring.
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
Spring 内部工作机制
Spring的AbstractApplicationContext 是ApplicationContect的抽象实现类,该抽象实现类的refresh()方法定义了Spring容器再加载配置文件后的各项处理过程。
- 1、初始化BeanFactory
初始化BeanFactory:根据配置文件实例化BeanFactory,在obtainFreshBeanFactory()方法中,首先调用refreshBeanFactory()方法刷新BeanFactory,然后调用getBeanFactory()方法获取BeanFactory,这两个方法都是由具体子类实现。在这一步里,Spring将配置文件的信息装入容器的Bean定义注册表(BeanDefinitionRegistry)中,但是此时Bean还没有初始化; - 2、调用工厂后处理器
根据反射机制从BeanDefinitionRegistry中找出所有实现了BeanFactoryPostProcessor接口的Bean,并调用其postProcessBeanFactory()接口方法; - 3、注册Bean后处理器
根据反射机制从BeanDefintionRegistry中找出所有实现了BeanPostProcessor接口的Bean,并将它们注册到容器Bean后处理的注册表; - 4、初始化消息源
initMessageSource()初始化容器的国际化消息资源; - 5、初始化应用上下文事件广播器;
- 6、初始化其他特殊的Bean
这是一个钩子方法。子类可以借助这个方法执行一些特殊的操作,如AbstractRefreshableWebApplicationContext就使用该方法执行初始化ThemeSource的操作; - 7、注册事件监听器;
- 8、初始化所有单实例的Bean,使用懒加载模式的Bean除外:
初始化Bean后,将它们放入Spring容器的缓存池中; - 9、初始化上下文刷新事件
创建上下文刷新事件,事件广播器负责将这些事件广播到每个注册的事件监听器中。
Spring ioc 原理
所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。核心为BeanFactory,实现机制为java反射
Bean生命周期
体过程如下:
1.当调用者通过getBean(beanName)向容器请求某一个Bean时,如果容器注册了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口,则在实例化Bean之前,将调用接口的postProcessBeforeInstantiation()方法;
2.根据配置情况调用Bean的构造函数或工厂方法实例化Bean;
3.如果容器注册了InstantiationAwareBeanPostProcessor接口,那么实例化Bean之后,调用该接口的postProcessAfterInstantiation()方法,可在这里对已经实例化的对象进行一些"梳妆打扮";
4.如果Bean配置了属性信息,那么容器在这一步着手将配置值设置到Bean对引发的属性中,不过在设置每个属性之前将先调用InstantiationAwareBeanPostProcessor接口的postProcessPorpertyValues()方法;
5.调用Bean的属性设置方法设置属性值;
6.如果Bean实现了org.springframework.beans.factory.BeanBaneAware接口则将调用setBeanName()接口方法,将配置文件中该Bean对应的名称设置到Bean中;
7.如果Bean实现了org.springframework.beans.factory.BeanFactoryAware接口,则将调用setBeanFactory()接口方法,将BeanFactory容器实例设置到Bean中;
8.如果BeanFactory装配了org.springframework.beans.factory.config.BeanPostProcessor后处理器,则将调用BeanPostProcessor的Object postProcesBeforeInitializaton(Object bean,String beanName)接口方法对Bean进行加工操作。其中,入参bean是当前正在处理的Bean,而beanName是当前的配置名,返回的对象为加工处理后的Bean。用户可以使用该方法对某些Bean进行特殊的处理,甚至改变Bean的行为。BeanPostProcessor在Spring框架中占有重要的地位,为容器提供对Bean进行后续加工处理的切入点,Spring容器所提供的各种"神奇功能"(AOP、动态代理等)都是通过BeanPostProcessor实施的;
9.如果Bean实现了InitializingBean接口,则将调用接口的afterPropertiesSet()方法;
10.如果配置文件中通过init-method属性定义了初始化方法,则将执行这个方法;
11.BeanPostProcessor后处理器定义了两个方法:其一是postProcessBeforeInitialization(),在第8步调用;其二是Object postProcessAfterInitialization(Object bean,String beanName),这个方法在此时调用,容器将再次获取对Bean进行加工处理的机会;
12.如果配置文件中指定Bean的作用范围为scope=“prototype”,则将Bean返回给调用者,调用者负责Bean后续生命的管理,Spring不在管理这个Bean的生命周期;如果将作用范围设置为scope=“singleton”,则将Bean放入Spring IoC容器的缓存池中,并将Bean引用返回调用者,Spring继续对这些Bean进行后续的生命管理;
13.对于scope="singleton"的Bean(默认情况),当容器关闭时,将触发Spring对Bean后续生命周期的管理工作。如果Bean实现了DisposableBean接口,则将调用接口的destory()方法,可以在此编写释放资源、记录日志等操作;
14.对于scope="singleton"的Bean,如果通过配置文件中的destory-method属性指定了Bean的销毁方法,那么Spring将执行Bean的这个方法,完成Bean资源的释放等操作。
Java反射
实现原理:
Class反射对象描述类语义结构,可以从Class对象中获取构造函数、成员变量、方法类等类元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作。这些反射对象类在java.reflect包中定义,下面是最主要的三个反射类:
Constructor:类的构造函数反射类,通过Class#getConstructors()方法可以获得类的所有构造函数反射对象数组。在JDK5.0中,还可以通过getConstructor(Class… parameterTypes)获取拥有特定入参的构造函数反射对象。Constructor的一个主要方法是newInstance(Object[] initargs),通过该方法可以创建一个对象类的实例,相当于new关键字。在JDK5.0中该方法演化为更为灵活的形式:newInstance (Object… initargs)。
Method:类方法的反射类,通过Class#getDeclaredMethods()方法可以获取类的所有方法反射类对象数组Method[]。在JDK5.0中可以通过getDeclaredMethod(String name, Class… parameterTypes)获取特定签名的方法,name为方法名;Class…为方法入参类型列表。Method最主要的方法是invoke(Object obj, Object[] args),obj表示操作的目标对象;args为方法入参,代码清单3 10③处演示了这个反射类的使用方法。在JDK 5.0中,该方法的形式调整为invoke(Object obj, Object… args)。此外,Method还有很多用于获取类方法更多信息的方法:
1)Class getReturnType():获取方法的返回值类型;
2)Class[] getParameterTypes():获取方法的入参类型数组;
3)Class[] getExceptionTypes():获取方法的异常类型数组;
4)Annotation[][] getParameterAnnotations():获取方法的注解信息,JDK 5.0中的新方法;
Field:类的成员变量的反射类,通过Class#getDeclaredFields()方法可以获取类的成员变量反射对象数组,通过Class#getDeclaredField(String name)则可获取某个特定名称的成员变量反射对象。Field类最主要的方法是set(Object obj, Object value),obj表示操作的目标对象,通过value为目标对象的成员变量设置值。如果成员变量为基础类型,用户可以使用Field类中提供的带类型名的值设置方法,如setBoolean(Object obj, boolean value)、setInt(Object obj, int value)等。
此外,Java还为包提供了Package反射类,在JDK 5.0中还为注解提供了AnnotatedElement反射类。总之,Java的反射体系保证了可以通过程序化的方式访问目标类中所有的元素,对于private或protected的成员变量和方法,只要JVM的安全机制允许,也可以通过反射进行调用,请看下面的例子:
代码清单3-12 PrivateCarReflect
publicclassPrivateCar{
//①private成员变量:使用传统的类实例调用方式,只能在本类中访问
privateStringcolor;
//②protected方法:使用传统的类实例调用方式,只能在子类和本包中访问
protectedvoiddrive(){
System.out.println("driveprivatecar!thecoloris:"+color);
}
}
//color变量和drive()方法都是私有的,通过类实例变量无法在外部访问私有变量、调用私有方法的,但通过反射机制却可以绕过这个限制:
publicclassPrivateCarReflect{
publicstaticvoidmain(String[]args)throwsThrowable{
ClassLoaderloader=Thread.currentThread().getContextClassLoader();
Classclazz=loader.loadClass("com.baobaotao.reflect.PrivateCar");
PrivateCarpcar=(PrivateCar)clazz.newInstance();
FieldcolorFld=clazz.getDeclaredField("color");
//①取消Java语言访问检查以访问private变量
colorFld.setAccessible(true);
colorFld.set(pcar,"红色");
MethoddriveMtd=clazz.getDeclaredMethod("drive",(Class[])null);
//MethoddriveMtd=clazz.getDeclaredMethod("drive");JDK5.0下使用
//②取消Java语言访问检查以访问protected方法
driveMtd.setAccessible(true);
driveMtd.invoke(pcar,(Object[])null);
}
}
//运行该类,打印出以下信息:
//引用
drive private car! the color is:红色
在访问private、protected成员变量和方法时必须通过setAccessible(boolean access)方法取消Java语言检查,否则将抛出IllegalAccessException。如果JVM的安全管理器设置了相应的安全机制,调用该方法将抛出SecurityException。
beanfactory和applicationcontext
Spring 通过一个配置文件来描述 Bean 及 Bean 之间的依赖关系,利用 Java 的反射功能实例化 Bean 并建立 Bean 之间的依赖关系 。Sprig 的 IoC 容器在完成这些底层工作的基础上,还提供了 Bean 实例缓存 、 生命周期管理 、Bean 实例代理 、 事件发布 、 资源装载等高级服务 。
Bean 工厂( com.springframework.beans.factory.BeanFactory )是 Spring 框架中最核心的接口,它提供了高级 IoC 的配置机制 。BeanFactory 使管理不同类型的 Java 对象成为可能。而应用上下文( com.springframework.context.ApplicationContext )建立在 BeanFactory 基础之上,提供了更多面向应用的功能,它提供了资源、国际化支持和框架事件体系,更易于创建实际应用 。我们一般称 BeanFactory 为 IoC 容器,而称 ApplicationContext 为应用上下文或 Spring 容器 。
BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身; ApplicationContext 面向使用 Spring 框架的开发者,几乎所有的应用场合都可以直接使用 ApplicationContext。
BeanFactory和FactoryBean
一般情况下,Spring通过反射机制利用bean的class属性制定实现类实例化bean。在默写情况下,实例化bean的过程比较复杂,需要提供大量的配置信息,配置方式的灵活性受限,这是采用编码的方式是一个简单的方案,用户可以通过实现该工厂类解耦实例化bean的逻辑,这是factoryBean作用就体现出来。
FactoryBean接口对于Spring框架来说占重要地位,Spring自身提供了很多FactoryBean的实现类。
BeanFactory是接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范,
FactoryBean也是接口,为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式(如果想了解装饰模式参考:修饰者模式(装饰者模式,Decoration)我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类.
FactoryBean支持的三个接口方法:
T getObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中;
Boolean isSingleton():返回由FactoryBean创建的Bean实例的作用域是singleton还是prototype;
Class getObjectType():返回FactoryBean创建的Bean类型。
类装载器ClassLoader
摘要:类装载器就是寻找类的字节码并构造出类在JVM内部表示对象的组件。在Java中,类装载器把一个类装入JVM中,需要经过以下几个步骤:1.装载:查找和导入Class文件,即Java字节码文件;2.链接:执行校验、准备和解析步骤,其中解析步骤是可以选择的:a)校验:检查载入的Class文件数据的正确性;b)装备:给类的静态变量分配存储空间(注意:这里仅仅为静态变量非配存储空间,而并未进行初始化操作,也就是说这时候静态变量还未被初始化)c)解析:将符号引用转成直接引用;3.链接:对类
类装载器就是寻找类的字节码并构造出类在JVM内部表示对象的组件。在Java中,类装载器把一个类装入JVM中,需要经过以下几个步骤:
- 装载:查找和导入Class文件,即Java字节码文件;
- 链接:执行校验、准备和解析步骤,其中解析步骤是可以选择的: a) 校验:检查载入的Class文件数据的正确性;
b) 装备:给类的静态变量分配存储空间(注意:这里仅仅为静态变量非配存储空间,而并未进行初始化操作,也就是说这时候静态变量还未被初始化)
c) 解析:将符号引用转成直接引用; - 链接:对类的静态变量、静态代码块执行初始化工作。
类装载工作由ClassLoader及其子类负责,它们负责在运行时查找和装入Class字节码文件。JVM在运行时会产生三个ClassLoader:根装载器、ExtClassLoader(扩展类装载器)和AppClassLoader(系统类装载器)。其中,根装载器不是ClassLoader的子类,它使用C++编写,而ExtClassLoader和AppClassLoader都是ClassLoader的子类。其中根装载器负责装载JRE的核心类库,如JRE目标下的rt.jar、charsets.jar等;ExtClassLoader负责装载JRE扩展目录ext中的JAR类包;AppClassLoader负责装载Classpath路径下的类包(即应用程序的类)。
这三个类装载器之间实际上存在父子层级关系,即根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。默认情况下,使用AppClassLoader装载应用程勋的类。
下面简单介绍一下JVM装载类的机制。JVM装载类时使用“全盘负责委托机制”,“全盘负责”是指当一个ClassLoader装载一个类时,除非显示地使用另一个ClassLoader,该类(被装载的类)所依赖及引用的类也由这个ClassLoader载入;“委托机制”是指委托父装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类(也就是在加载每个Class时,都会先由父装载器尝试寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类,此时则使用AppClassLoader。顺序依次是:根装载器–ExtClassLoader–AppClassLoader)。这一点是从安全角度考虑的,试想如果有人编写了一个恶意的基础类(如java.lang.String)并装载到JVM中将会引发多么可怕的结果。但是由于有了“全盘负责委托机制”,java.lang.String永远是由根装载器来装载的,这样就避免了上述事件的发生。
Spring aop 原理
说起AOP就不得不说下OOP了,OOP中引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。但是,如果我们需要为部分对象引入公共部分的时候,OOP就会引入大量重复的代码。例如:日志功能。
AOP技术利用一种称为“横切”的技术,解剖封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,这样就能减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。
方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用spring的 Advisor或拦截器实现。
AOP重要术语
- 连接点(Joinpoint): 程序执行过程中某个特定的位置,如方法的调用或特定的异常被抛出。
- 通知(Advice): 在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Spring中定义了四个advice: BeforeAdvice, AfterAdvice, ThrowAdvice和DynamicIntroductionAdvice
- 切入点(Pointcut): 指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点:例如,使用正则表达式。 Spring定义了Pointcut接口,用来组合MethodMatcher和ClassFilter,可以通过名字很清楚的理解, MethodMatcher是用来检查目标类的方法是否可以被应用此通知,而ClassFilter是用来检查Pointcut是否应该应用到目标类上
- 引入(Introduction): 添加方法或字段到被通知的类。 Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现 IsModified接口,来简化缓存。Spring中要使用Introduction, 可有通过DelegatingIntroductionInterceptor来实现通知,通过DefaultIntroductionAdvisor来配置Advice和代理类要实现的接口
- 目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。POJO
- AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
- 织入(Weaving): 组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
- 切面(Aspect):切面有切点、通知、引介组成,它既包括横切逻辑定义,也包括连接点定义
Aop代理
静态代理
动态代理:
JDK 动态代理
cgLib动态代理
Spring aop 使用两种代理机制:一种基于JDK 的动态代理;另一种是基于CGLib动态代理。原因:JDK本身值提供接口的代理,而不支持类的代理,当接口(JDK代理),当类(CGLIB)
JDK动态代理:
代理模式的UML图
从UML图中,可以看出代理类与真正实现的类都是继承了抽象的主题类,这样的好处在于代理类可以与实际的类有相同的方法,可以保证客户端使用的透明性。
代理模式的实现
代理模式可以有两种实现的方式,一种是静态代理类,另一种是各大框架都喜欢的动态代理。下面我们主要讲解一下这两种代理模式
静态代理
我们先看针对上面UML实现的例子,再看静态代理的特点。
//Subject接口的实现
public interface Subject {
void visit();
}
//实现了Subject接口的两个类:
public class RealSubject implements Subject {
private String name = "byhieg";
@Override
public void visit() {
System.out.println(name);
}
}
public class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void visit() {
subject.visit();
}
}
//具体的调用如下:
public class Client {
public static void main(String[] args) {
ProxySubject subject = new ProxySubject(new RealSubject());
subject.visit();
}
}
通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。
动态代理
动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。
其步骤如下:
编写一个委托类的接口,即静态代理的(Subject接口)
实现一个真正的委托类,即静态代理的(RealSubject类)
创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法
在测试类中,生成动态代理的对象。
第一二步骤,和静态代理一样,不过说了。第三步,代码如下:
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(object, args);
return result;
}
}
第四步,创建动态代理的对象
Subject realSubject = new RealSubject();
DynamicProxy proxy = new DynamicProxy(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, proxy);
subject.visit();
创建动态代理的对象,需要借助Proxy.newProxyInstance。该方法的三个参数分别是:
ClassLoader loader表示当前使用到的appClassloader。
Class<?>[] interfaces表示目标对象实现的一组接口。
InvocationHandler h表示当前的InvocationHandler实现实例对象。
Cglib代理: 针对类来实现代理,对指定目标
产生一个子类 通过方法拦截技术拦截所有父类方法的调用。
我们要使用cglib代理必须引入 cglib的jar包
//轮船类
package com.zs.spring.demo1;
public class Ship {
public void travel(){
System.out.println("轮船正在行驶");
}
//代理类 输出日志
package com.zs.spring.demo1;
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 ShipProxy implements MethodInterceptor {
//通过Enhancer 创建代理对象
private Enhancer enhancer = new Enhancer();
//通过Class对象获取代理对象
public Object getProxy(Class c){
//设置创建子类的类
enhancer.setSuperclass(c);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method m, Object[] args, MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
System.out.println("日志开始...");
//代理类调用父类的方法
proxy.invokeSuper(obj, args);
System.out.println("日志结束...");
return null;
}
}
//创建我的测试类
package com.zs.spring.demo1;
public class TestCgibl {
public static void main(String[] args) {
//创建我们的代理类
ShipProxy Proxy = new ShipProxy();
Ship ship = (Ship)Proxy.getProxy(Ship.class);
ship.travel();
}
}
输出:
日志开始…
轮船正在行驶
日志结束…
外传
😜 原创不易,如若本文能够帮助到您的同学
🎉 支持我:关注我+点赞👍+收藏⭐️
📝 留言:探讨问题,看到立马回复
💬 格言:己所不欲勿施于人 扬帆起航、游历人生、永不言弃!🔥