相信大家都对spring 很所了解 ,spring ioc 和aop 也是它的重要的,也是它的基础
现在聊一下在没有spring AOP中在只有jdk自带的开发包怎么实现
下面就是实现的代码:
*
*/
package SpringAop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//import java.util.logging.Logger;
//import java.util.logging.Level;
import java.lang.reflect.Proxy;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
/**//**
* @author Administrator
* @date or time 2007-1-5 23:08:30
* @project AppTest
*/
//首先创建一个接口--在面向对象语言提倡面向接口
interface IToApplyForJob
...{
public void sayForward(String corporation);
}
class ToApplyForJobImpl implements IToApplyForJob//实现接口的类
...{
public void sayForward(String corporation) ...{
// TODO 呵呵。
System.out.println("没有别的意思,现在还没有工作,我向"+corporation+"就职应聘");
}
}
//自定义调用处理类必须实现InvocationHandler,InvocationHandler 是代理实例的调用处理程序 实现的接口
class ForJobHandler implements InvocationHandler
...{ Object delegate;
public ForJobHandler(Object delegate)
...{
this.delegate=delegate;
}
Logger logger=Logger.getLogger(this.getClass().getName());//跟log4j一样要得到类名
public Object invoke(Object proxy, Method method, Object... args) throws Throwable ...{
// TODO 这里就是在spring中AOP中的aroundAdvice
logger.log(Level.INFO,"大学生活快结束了");
System.out.println("大学生活快结束了");
Object target=method.invoke(delegate,args);//这个就是用来调用要调用的方法
System.out.println("本人还是很喜欢java");
logger.log(Level.INFO,"本人还是很喜欢java");
return target;
}
}
public class AOPTest ...{
public static void main(String[] args) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
...{
//创建一个目标对象
IToApplyForJob job=new ToApplyForJobImpl();
//构造一个handle
ForJobHandler handle=new ForJobHandler(job);
//方法一
//返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
//IToApplyForJob target=(IToApplyForJob) Proxy.newProxyInstance(job.getClass().getClassLoader(),job.getClass().getInterfaces(),handle);
//方法二
//构造IToApplyForJob的代理类
Class proxyClass = Proxy.getProxyClass(
IToApplyForJob.class.getClassLoader(), new Class[] ...{ IToApplyForJob.class });
IToApplyForJob target=(IToApplyForJob)proxyClass.getConstructor(new Class[] ...{ InvocationHandler.class }).newInstance(new Object[] ...{ handle });
target.sayForward("全国企业");
}
}
这个把日志切入到业务方法的之前和之后就像 SpringAOP 中的AroundAdvice
结果就是
大学生活快结束了
没有别的意思,现在还没有工作,我向全国企业就职应聘
本人还是很喜欢java
14:07:16,468 INFO ForJobHandler:53 - 本人还是很喜欢java
在jdk帮助文档中这样解释的
创建某一接口 IToApplyForJob 的代理:
这里比较重要的两个方法就是proxy.newProxyInstance和method.invoke
其中
Class proxyClass = Proxy.getProxyClass(
IToApplyForJob.class.getClassLoader(), new Class[] ...{ IToApplyForJob.class });
IToApplyForJob target=(IToApplyForJob)proxyClass.getConstructor(new Class[] ...{ InvocationHandler.class }).newInstance(new Object[] ...{ handle });
或使用以下更简单的方法:
IToApplyForJob target=(IToApplyForJob) Proxy.newProxyInstance(job.getClass().getClassLoader(),job.getClass().getInterfaces(),handle);
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
代理类具用以下属性:
代理类是公共的、最终的,而不是抽象的。
未指定代理类的非限定名称。但是,以字符串 "$Proxy" 开头的类名空间应该为代理类保留。
代理类扩展 java.lang.reflect.Proxy。
代理类会按同一顺序准确地实现其创建时指定的接口。
如果代理类实现了非公共接口,那么它将在与该接口相同的包中定义。否则,代理类的包也是未指定的。注意,包密封将不阻止代理类在运行时在特定包中的成功定义,也不会阻止相同类加载器和带有特定签名的包所定义的类。
由于代理类将实现所有在其创建时指定的接口,所以对其 Class 对象调用 getInterfaces 将返回一个包含相同接口列表的数组(按其创建时指定的顺序),对其 Class 对象调用 getMethods 将返回一个包括这些接口中所有方法的 Method 对象的数组,并且调用 getMethod 将会在代理接口中找到期望的一些方法。
如果 Proxy.isProxyClass 方法传递代理类(由 Proxy.getProxyClass 返回的类,或由 Proxy.newProxyInstance 返回的对象的类),则该方法返回 true,否则返回 false。
代理类的 java.security.ProtectionDomain 与由引导类加载器(如 java.lang.Object)加载的系统类相同,原因是代理类的代码由受信任的系统代码生成。此保护域通常被授予 java.security.AllPermission。
每个代理类都有一个可以带一个参数(接口 InvocationHandler 的实现)的公共构造方法,用于设置代理实例的调用处理程序。并非必须使用反射 API 才能访问公共构造方法,通过调用 Proxy.newInstance 方法(将调用 Proxy.getProxyClass 的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。
代理实例具有以下属性:
提供代理实例 proxy 和一个由其代理类 Foo 实现的接口,以下表达式将返回 true:
proxy instanceof IToApplyForJob
并且以下的强制转换操作将会成功(而不抛出 ClassCastException):
(IToApplyForJob) proxy
每个代理实例都有一个关联的调用处理程序,它会被传递到其构造方法中。静态 Proxy.getInvocationHandler 方法将返回与作为其参数传递的代理实例相关的调用处理程序。
代理实例上的接口方法调用将按照该方法的文档描述进行编码,并被指派到调用处理程序的 Invoke 方法。
在代理实例上的 java.lang.Object 中声明的 hashCode、equals 或 toString 方法的调用将按照与编码和指派接口方法调用相同的方式进行编码,并被指派到调用处理程序的 invoke 方法,如上所述。传递到 invoke 的 Method 对象的声明类是 java.lang.Object。代理类不重写从 java.lang.Object 继承的代理实例的其他公共方法,所以这些方法的调用行为与其对 java.lang.Object 实例的操作一样。
在多代理接口中重复的方法
如果代理接口包含某一方法,它的名称和参数签名与 java.lang.Object 的 hashCode、equals 或 toString 方法相同,那么在代理实例上调用这样的方法时,传递到调用处理程序的 Method 对象将使 java.lang.Object 成为其声明类。换句话说,java.lang.Object 公共的非最终方法理论上在所有代理接口之前,以便确定哪一个 Method 对象传递到调用处理程序。
还要注意,当重复方法被指派到调用处理程序时,invoke 方法只可以抛出经过检查的异常类型,该异常类型可以使用所有 代理接口(可以通过它调用)中方法的 throws 子句指派一种异常类型。如果 invoke 方法抛出一个经过检查的异常,该异常没有指派给任何由一个代理接口(可以通过它调用)中的方法声明的异常类型,那么该代理实例上的调用将抛出一个未经检查的 UndeclaredThrowableException。此限制表示并非所有的由传递到 invoke 方法的 Method 对象上调用 getExceptionTypes 返回的异常类型都可以由 invoke 方法成功抛出。
//////////////////////////////////////////////////////////////////////////////
public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler h)
throws IllegalArgumentException返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。此方法相当于:
Proxy.getProxyClass(loader, interfaces).
getConstructor(new Class[] ...{ InvocationHandler.class }).
newInstance(new Object[] ...{ handler });
Proxy.newProxyInstance 抛出 IllegalArgumentException,原因与 Proxy.getProxyClass 相同。
参数:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
返回:
一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
抛出:
IllegalArgumentException - 如果违反传递到 getProxyClass 的参数上的任何限制
NullPointerException - 如果 interfaces 数组参数或其任何元素为 null,或如果调用处理程序 h 为 null
//////////////////////////////////////////////////////////////////////////////////
public static Class getProxyClass(ClassLoader loader,
Class... interfaces)
throws IllegalArgumentException返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。该代理类将由指定的类加载器定义,并将实现提供的所有接口。如果类加载器已经定义了具有相同排列接口的代理类,那么现有的代理类将被返回;否则,类加载器将动态生成并定义这些接口的代理类。
对可以传递给 Proxy.getProxyClass 的参数有以下几个限制:
interfaces 数组中的所有 Class 对象必须表示接口,而不能表示类或基本类型。
interfaces 数组中的两个元素不能引用同一 Class 对象。
所有接口类型的名称通过特定的类加载器必须可见。换句话说,对于类加载器 cl 和所有接口 i,以下表达式必须为 true:
Class.forName(i.getName(), false, cl) == i
所有非公共接口必须位于同一包中;否则,该代理类将不可能实现所有的接口,无论它在哪一个包中定义。
对于有相同签名的指定接口中任何成员方法集:
如果任何方法的返回类型是基本类型或 void,那么所有的方法必须具有与此相同的返回类型。
否则,该方法之一必须是返回类型,它可以指派给该方法其余的所有返回类型。
得到的代理类必须不超过虚拟机在类上施加的任何限制。例如,虚拟机可以限制某一类实现至多 65535 的接口数;在这种情况下,interfaces 数组的大小必须不超过 65535。
如果违反了这些限制,Proxy.getProxyClass 将抛出 IllegalArgumentException。如果 interfaces 数组参数或其任何元素为 null,则将抛出 NullPointerException。
注意,指定的代理接口的顺序非常重要:对接口组合相同但顺序不同的代理类的两个请求会导致两个不同的代理类。
参数:
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
返回:
用指定的类加载器定义的代理类,它可以实现指定的接口
抛出:
IllegalArgumentException - 如果违反传递到 getProxyClass 的参数上的任何限制
NullPointerException - 如果 interfaces 数组参数或其任何元素为 null
///////////////////////////////////////////////////////////////////////////////////
public Object invoke(Object obj,
Object... args)
throws IllegalAccessException,
IllegalArgumentException,
InvocationTargetException对带有指定参数的指定对象调用由此 Method 对象表示的基础方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。
如果基础方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
如果基础方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。
如果基础方法是实例方法,则使用动态方法查找来调用它,这一点记录在 Java Language Specification, Second Edition 的第 15.12.4.4 节中;在发生基于目标对象的运行时类型的重写时更应该这样做。
如果基础方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。
如果方法正常完成,则将该方法返回的值返回给调用方;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不 被包装在对象中;换句话说,将返回基本类型的数组。如果基础方法返回类型为 void,则该调用返回 null。
参数:
obj - 从中调用基础方法的对象
args - 用于方法调用的参数
返回:
使用参数 args 在 obj 上指派该对象所表示方法的结果
抛出:
IllegalAccessException - 如果此 Method 对象强制执行 Java 语言访问控制,并且基础方法是不可访问的。
IllegalArgumentException - 如果该方法是实例方法,且指定对象参数不是声明基础方法的类或接口(或其中的子类或实现程序)的实例;如果实参和形参的数量不相同;如果基本参数的解包转换失败;如果在解包后,无法通过方法调用转换将参数值转换为相应的形参类型。
InvocationTargetException - 如果基础方法抛出异常。
NullPointerException - 如果指定对象为 null,且该方法是一个实例方法。
ExceptionInInitializerError - 如果由此方法引起的初始化失败。
相关推荐
Spring AOP则是在Spring框架中对AOP概念的实现,它利用了JDK动态代理或CGLIB(字节码增强)来实现。Spring AOP的主要目标是分离关注点,将非业务逻辑(如日志、事务管理)从核心业务代码中解耦出来。以下是Spring ...
7. **JDK动态代理或CGLIB**:Spring AOP在没有找到AspectJ的情况下的默认代理实现,用于创建代理对象以插入切面。 压缩包"aop-environment"很可能包含了上述部分或全部组件,为开发者提供了一个即用型的AOP开发环境...
在Java中,可以使用java.lang.reflect包下的相关类和接口实现动态代理。 例如,通过使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口,我们可以在运行时创建一个代理对象。代理对象在调用...
在实际开发中,我们可以通过注解驱动的方式简化AOP配置,例如`@Aspect`用于标记切面类,`@Before`、`@After`等用于定义通知,`@Pointcut`用于定义切入点。 通过理解并熟练掌握Spring AOP,开发者可以编写出更加整洁...
在实际开发中,我们可以通过以下步骤来利用Spring AOP和AspectJ: 1. 定义切面:创建一个Java类,使用`@Aspect`注解标记,然后在这个类中定义切入点表达式(@Pointcut)和通知(@Before、@After、@Around、@After...
在Java开发中,AOP(面向切面编程)是一种重要的编程范式,它允许程序员将关注点分离,比如日志、事务管理等通用功能,从核心业务逻辑中解耦出来。Spring框架是Java世界里AOP应用的典型代表。本文将深入探讨Spring是...
在实际开发中,我们还需要了解切点表达式的编写,如"execution(* com.example.service.*.*(..))"用于匹配com.example.service包下的所有类的所有方法。此外,还需要掌握通知的执行顺序,以及如何处理异常和事务控制...
在Spring AOP中,当目标对象实现了至少一个接口时,Spring会使用JDK的动态代理来创建代理对象。这是因为JDK的动态代理只适用于实现了接口的类,它通过生成一个与目标类接口相同的新类来实现代理。这个新类在运行时被...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改代码的情况下,通过插入切面来增强或改变已有功能的能力。...在实际项目中,合理利用AOP能有效提升开发效率,实现业务需求。
在提供的 `lib` 压缩包中,应包含 Spring AOP 和 Spring IOC 相关的 jar 包,如 `spring-aop-x.x.x.jar` 和 `spring-context-x.x.x.jar` 等,它们是使用这两个功能的基础。请确保引入正确的版本,并正确配置到项目的...
在Java领域,我们可以使用Spring框架提供的AOP支持,但本实例主要讨论的是如何使用JDK自身的动态代理(Proxy)技术来实现AOP。 JDK的Proxy类提供了创建动态代理对象的能力,这个代理对象可以代表一个或多个实现了...
这些 jar 包的组合使用,构建了一个完整的 Spring AOP 环境,允许开发人员方便地定义切面,创建切入点,定义通知,以及选择合适的代理模式(如 JDK 动态代理或 CGLIB 代理)。这样,我们可以将关注点分离,提高代码...
在Spring中,AOP代理有两种实现方式:JDK动态代理和CGLIB代理。JDK代理适用于实现了接口的类,而CGLIB代理则适用于未实现接口的类。 1. **JDK动态代理**: - Spring通过实现`java.lang.reflect.InvocationHandler`...
本篇文章主要介绍了如何利用Java动态代理技术实现AOP的基本原理及其在实际开发中的应用。 #### AOP核心概念 AOP的核心概念包括: - **切面(Aspect)**:一个关注点的模块化,它可以跨越多个对象的行为。例如,...
7. **代理(Proxy)**:应用通知的对象,Spring通常使用JDK动态代理或CGLIB实现。 8. **织入(Weaving)**:将切面应用到目标对象以创建代理对象的过程,可以在编译时、类加载时或运行时进行。 **第一种:经典的基于...
CGLIB是一个强大的高性能的代码生成库,它会在运行期动态生成子类并覆盖父类的方法来实现AOP的功能。 **4. 配置Spring AOP** 在Spring XML配置文件中,我们可以定义以下元素来实现AOP配置: - `<aop:config>`:声明...
在Java开发领域,Spring框架是广泛应用的一个开源框架,它提供了许多功能,其中之一就是面向切面编程(Aspect-Oriented Programming,简称AOP)。AOP是一种编程范式,它旨在提高软件的可维护性和可扩展性,通过将...
Spring的AOP代理(无论是JDK还是CGLIB)都会实现这个接口,并在intercept()方法中插入通知逻辑。 此外,Spring还提供了基于注解的AOP支持,如@Aspect、@Before、@After等,这使得AOP的使用更加便捷。在编译时,...
在IT开发领域,AOP(面向切面编程)是一种强大的编程范式,它允许程序员将关注点分离到各个切面,比如日志记录、事务管理等,而不必在每个具体的业务方法中显式处理这些通用任务。Spring AOP是Spring框架的一部分,...
在实际的开发中,AOP通常用于实现日志记录、事务管理、性能监控等功能,这些功能被称为“横切关注点”,因为它们横跨多个类或方法。 在Spring AOP中,我们定义了以下几个核心概念: 1. **切面(Aspect)**:这是...