在一个服务的流程中插入与业务逻辑无关的系统服务逻辑(如logginng,security),这样的逻辑称为cross-cutting concerns,将cross-cutting concerns独立出来设计为一个对象,这样的特殊对象称为Aspect,Aspect-oriented programming着重在Aspect的设计及与应用程序的织入(Weave)。
spring实现aop的方式之一是代理机制:
例如:当执行某些方法时候需要记录日志:一般这么写:
public class HelloSpeak(){
private logger = Logger.getLogger(this.getClass().getName());
public void sayHello(){
logger.log(Level.Info,"begin");
system.out.println("zzheng zai zhi xing");
logger.log(Level.Info,"end");
}
}
对于HelloSpeaker来说,记录日志的方法不是他的业务逻辑,这么做增加了他额外的职责,如果很多类都这么做,程序会很混乱。特别是还有其他的职能:如事务检查,安全处理,权限检查等。
可以使用代理(Proxy)机制来解决这个问题,在这边讨论两种代理方式:静态代理(Static proxy)与动态代理(Dynamic proxy)。
静态代理
在静态代理的实现中,代理对象与被代理的对象都必须实现同一个接口,在代理对象中可以实现日志记录等相关服务,并在需要的时候再呼叫被代理的对象,如此代理对象当中就可以仅保留业务相关职责。举个实际的例子来说,首先定义一个IHello接口:
package aop;
public interface Ihello {
public void sayHello();
}
然后让实现业务逻辑的HelloSpeaker类实现IHello接口,例如:
package aop;
public class HelloSpeak implements Ihello {
public void sayHello() {
System.out.println("ni hao.");
}
}
在HelloSpeaker类中现在没有任何记录的程序代码插入其中,日志记录服务的实现将被放至代理对象之中,代理对象同样也要实现IHello接口,例如
public class HelloProxy implements Ihello {
private Logger logger = Logger.getLogger(this.getClass().getName());
private Ihello hellotest;
public HelloProxy(Ihello hellotest) {
this.hellotest = hellotest;
}
public void sayHello() {
log("begin ************");
hellotest.sayHello();
System.out.println("****" + logger);
log("end **********");
}
private void log(String msg) {
logger.log(Level.INFO, msg);
}
}
测试类如下:
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
HelloSpeak hs = new HelloSpeak();
HelloProxy hp = new HelloProxy(hs);
hp.sayHello();
}
}
代理对象的一个接口只服务于一种类型的对象,而且如果要代理的方法很多,势必要为每个方法进行代理,静态代理在程序规模稍大时就无法胜任。
动态代理
在JDK1.3之后加入了可协助开发动态代理功能的API,您不必为特定对象与方法编写特定的代理对象,使用动态代理,可以使得一个处理者(Handler)服务于各个对象。首先,一个处理者的类设计必须实现java.lang.reflect.InvocationHandler接口,以实例来进行说明,例如设计一个LogHandler类
package dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LogHandler implements InvocationHandler {
private Logger log = Logger.getLogger(this.getClass().getName());
private Object delegate;
public Object bind(Object delegate){
this.delegate = delegate;
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
this.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
try{
log("begin *********"+method);
result = method.invoke(delegate, args);
log("end *****"+method);
}catch(Exception e){
log(e.toString());
}
return result;
}
private void log(String msg){
log.log(Level.INFO,msg);
}
}
主要的概念是使用Proxy .newProxyInstance ()静态方法建立一个代理对象,建立代理对象时必须告知所要代理的接口,之后您可以操作所建立的代理对象,在每次操作时会执行InvocationHandler的invoke()方法,invoke ()方法会传入被代理对象的方法名称与执行参数,实际上要执行的方法交由method.invoke(),您在method.invoke()前后加上记录动作,method.invoke ()传回的对象是实际方法执行过后的回传结果。要实现动态代理,同样必须定义所要代理的接口,例如
package dynamic;
public interface Ihello {
public void sayHello();
}
然后让实现业务逻辑的HelloSpeaker类实现IHello接口,例如:
public class HelloSpeak implements Ihello {
public void sayHello() {
System.out.println("ni hao.");
}
}
编写一个测试的程序,您要使用LogHandler的bind ()方法来绑定被代理对象,如下所示:
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
LogHandler lh = new LogHandler();
HelloSpeak ee = new HelloSpeak();
Ihello tt = (Ihello) lh.bind(ee);
tt.sayHello();
}
}
LogHandler不再服务于特定对象与接口,而HelloSpeaker也不用插入任何有关于记录的动作,它不用意识到记录动作的存在。
以上例子中,HelloSpeake本身的职责是显示招呼文字,却必须插入记录(Log)动作,这使得HelloSpeaker 的职责加重,在 AOP的术语来说,记录的程序代码横切(Cross-cutting)入HelloSpeaker的程序执行流程中,记录这样的动作在AOP中称之为横切关切点 (Cross-cutting concern)。
使用代理对象将记录等与业务逻辑无关的动作或任务提取出来,设计为一个服务对象,像是之前范例中示范的HelloProxy或是LogHandler,这样的对象称之为切面(Aspect)。
AOP中的Aspect所指的可以像是记录等这类的动作或服务,您将这些动作(Cross-cutting concems)设计为通用、不介入特定业务对象的一个职责清楚的Aspect对象,这就是所谓的Aspect-oriented programming,缩写名词即为 AOP 。
在好的设计之下, Aspect可以独立于应用程序之外,在必要的时候,可以介入应用程序之中提供服务,而不需要相关服务的时候,又可以将这些Aspect直接从应用程序中脱离,而应用程序本身不需修改任何一行程式码。
分享到:
相关推荐
在 Spring AOP 中,`org.springframework.aop.framework.JdkDynamicAopProxy` 类实现了 `InvocationHandler` 接口,当代理对象的方法被调用时,实际会执行 `JdkDynamicAopProxy.invoke()` 方法。这个方法会检查并...
Spring使用CGLIB包中的Enhancer类来生成代理对象。当目标对象没有实现接口时,Spring会自动选择CGLIB作为默认的代理方式。 在Spring Boot项目中,配置和使用AOP相对简单。首先,我们需要引入Spring AOP和AspectJ的...
代理对象负责拦截方法调用并执行相关的通知。 在实际应用中,Spring AOP常用于以下场景: 1. 日志记录:在方法调用前后记录日志信息。 2. 事务管理:确保一组数据库操作作为原子操作进行,如果出现异常则全部回滚。...
织入(Weaving)是将切面应用到目标对象以创建新的代理对象的过程,这在Spring中通常是自动完成的。 在Spring Boot项目中启用AOP,我们需要以下步骤: 1. **引入依赖**:在`pom.xml`或`build.gradle`文件中添加...
总结,Spring中的AOP代理是实现切面编程的关键机制,它通过JDK动态代理或CGLIB代理来创建代理对象,并在方法调用时插入切面逻辑。理解和熟练运用AOP代理能够极大地提高代码的可维护性和复用性,是Spring开发者必备的...
5. **代理的使用**:在应用中,我们通常不直接引用目标对象,而是通过ApplicationContext获取Bean,此时Spring会自动创建并返回相应的代理对象。这样,当我们调用代理对象的方法时,就会触发AOP代理逻辑。 6. **切...
如果被代理的类没有实现接口,Spring AOP会采用CGLIB来生成代理对象。CGLIB(Code Generation Library)是一个开源的代码生成库,它允许运行时在内存中动态生成类和对象。 在Spring AOP中,我们通常使用@Aspect注解...
本文将深入探讨如何在Spring中通过自定义工具类获取代理对象所代理的目标对象。 ### 核心概念:AOP与Spring Proxy 在理解如何获取目标对象之前,我们需要先了解Spring AOP的实现机制。Spring AOP主要通过动态代理...
- **测试类**:用于演示如何使用Spring.NET容器获取代理对象并进行调用,验证AOP功能是否正确工作。 要运行此示例,你需要: 1. 设置Spring.NET配置,指定需要代理的对象、切面和代理类型。 2. 创建切面类,定义要...
即使你没有直接使用AspectJ语法编写切面,Spring的AOP代理也可以利用这个库进行代理对象的创建,以实现方法调用前后的通知(advises)。这个库对于那些希望在不改变源代码的情况下,通过AOP增强已有类的行为的开发者...
- 代理(Proxy):Spring创建的对象,用于在实际的目标对象前后插入通知。可以是JDK动态代理或CGLIB代理。 五、应用场景 Spring AOP常用于以下场景: - 日志记录:在方法执行前后记录日志信息。 - 事务管理:自动...
Spring AOP可以利用JDK动态代理来实现对方法的拦截,当调用目标对象的方法时,实际上执行的是代理对象的方法,从而实现在方法执行前后加入额外逻辑。 以下是使用JDK动态代理实现Spring AOP的步骤: 1. **定义切面...
三、Spring AOP代理原理 Spring AOP通过两种代理机制实现: 1. JDK动态代理:只能代理实现了接口的目标对象,性能相对较低,需要指定代理接口。 2. CGLIB代理:可代理接口和非final的类,性能较高,通过生成字节...
spring-aop.jar包含了这些代理机制的相关类,如`org.springframework.aop.framework.ProxyFactoryBean`,它是创建代理对象的工厂。 2. **切面(Aspect)**:切面是AOP的核心概念,它封装了关注点的逻辑。在Spring中...
5. **代理(Proxy)**:Spring AOP通过动态代理机制创建目标对象的代理,代理对象负责拦截方法调用并执行通知。有两种代理类型:JDK动态代理和CGLIB代理。JDK代理用于实现了接口的目标对象,而CGLIB代理则用于没有...
Spring AOP代理是框架为实现切面功能创建的对象,它在运行时实现切面协议。Spring提供了两种代理方式:JDK动态代理和CGLIB代理。JDK代理适用于那些实现了接口的类,而CGLIB代理则适用于没有实现接口的类。 引介...
6. 目标对象(Target Object):被AOP代理的对象。 7. 代理(Proxy):AOP框架创建的对象,它实现了目标对象的所有接口并拦截方法调用以执行通知。 在Spring配置文件中,我们可以通过以下方式引用`spring-aop.xsd`...
为了说明Spring的AOP原理,本人使用代理模式中的动态代理完成演示AOP编程的原理的演示。相信,如果你耐心看完整个程序(几乎一行注释一行代码),那么你对Spring这个东西就不是觉得有什么神秘了! 阅读对象:凡是喜爱...
在Spring AOP中,主要涉及以下几个核心概念: 1. **切面(Aspect)**:切面是关注点的模块化,比如日志记录、事务管理、性能监控等。在Spring AOP中,切面由通知(Advice)和切点(Pointcut)定义。 2. **通知...