如果系统中有500个类,每个类都要添加日志功能,此时无论是直接修改源代码、继承还是组合,都是十分巨大的工作量。此时AOP可以帮我们解决这个问题。
现在假设记录日志的功能已经单独提出来了,由LogInterceptor来完成:
package com.bjsxt.aop;
public class LogInterceptor {
public void beforeMethod() {
System.out.println("logging...");
}
}
有了Spring AOP,我们就可以用配置文件来说明:“在某个类的每一个方法执行之前,都给我调用一次beforeMethod()方法”(更复杂一点的做法是给beforeMethod()方法添加一个Method参数,这样可以配置可以具体到某个类的某个方法上),如:
<beans>
<bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl" >
<!-- 非标准写法,仅作演示 -->
<Log class="com.bjsxt.aop.LogInterceptor" logMethod="beforeMethod" targetMethod="all" />
</bean>
</beans>
这样,在配置文件中给500个bean都加上这么一段,就能给这500个类都加上日志功能了。
那么Spring AOP是如何实现的呢?用的是动态代理的方法。
参考[#0x0022],我们可以把LogInterceptor实现成一个InvocationHandler
package com.bjsxt.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LogInterceptor implements InvocationHandler {
private Object target;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public void beforeMethod(Method m) {
System.out.println(m.getName() + ": logging...");
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
beforeMethod(m);
m.invoke(target, args);
return null;
}
}
调用的代码如下:
public class AOPTest
{
public static void main(String[] args)
{
UserDAO userDAO = new UserDAOImpl();
LogInterceptor li = new LogInterceptor();
li.setTarget(userDAO);
UserDAO userDAOProxy = (UserDAO)Proxy.newProxyInstance(userDAO.getClass().getClassLoader(), userDAO.getClass().getInterfaces(), li);
userDAOProxy.save(new User());
}
}
这里要特殊说明的是:
(1) userDAOProxy对象是UserDAOImpl类的动态代理,userDAOProxy是代理对象,UserDAOImpl对象是被代理对象;
(2) 若想用Java API来给某个类(如UserDAOImpl)来创建动态代理,那么这个类必须实现一个接口(如UserDAO),没有实现接口的类用Java API是无法创建动态代理的(但cglib可以)。所以在Proxy.newProxyInstance()方法中,需要把被代理类的接口,即userDAO.getClass().getInterfaces()传递进去。
(3) 代理对象和被代理对象应该在同一个classLoader中,如果在不同的classLoader中,它们就无法互相访问,所以userDAO.getClass().getClassLoader()也作为参数传递给了Proxy.newProxyInstance()。代理对象和被代理对象需要互相访问的原因在(4)
(4) 我们得到的userDAOProxy对象,其类型应该是一个组合了LogInterceptor的类(li作为参数被传递给了Proxy.newProxyInstance()),而LogInterceptor又组合了userDAOImpl(li.setTarget(userDAO));加上userDAOProxy又实现了UserDAO接口,所以userDAOProxy看上去应该是这样一个类:
// 非标准写法,仅作演示用
public class UserDAOProxy implements UserDAO {
private InvocationHandler invocationHandler;
public UserDAOProxy(InvocationHandler invocationHandler) {
super();
this.invocationHandler = invocationHandler;
}
public InvocationHandler getInvocationHandler() {
return invocationHandler;
}
public void save(User user) {
this.invocationHandler.invoke(proxy, UserDAO.class.getDeclaredMethod("save", User.class), user);
}
}
(同[#0x0022],invoke()方法中的proxy对象还是不知道是干嘛用的……视频中说这个proxy对象就是userDAOProxy自身,待研究)
这样,Proxy.newProxyInstance(userDAO.getClass().getClassLoader(), userDAO.getClass().getInterfaces(), li)也就相当于new UserDAOProxy(li)。userDAOProxy的save()方法的实际过程是:

Spring AOP为系统添加逻辑(业务逻辑,如上文的日志)的动态代理方法大抵就是这样。
如果UserDAO还有个delete()方法,那么userDAOProxy.delete()也会去调用li.invoke(proxy, delete, user)。这就体现了InvocationHandler是“对被代理对象的任意方法的invocation都handle”这么一个概念。
当然,更好的实现是把beforeMethod这部分逻辑提出来,让LogInterceptor这个类侧重“Interceptor”而不包含"Log"的逻辑,beforeMethod完全可以用一个Logger类来实现

- 大小: 10.5 KB
分享到:
相关推荐
在Spring中,AOP主要通过两种动态代理技术实现:JDK动态代理和CGLIB动态代理。 首先,让我们详细了解一下JDK动态代理。JDK动态代理基于Java的接口实现,它适用于目标对象实现了至少一个接口的情况。在运行时,JDK...
本资源主要涵盖了静态代理和动态代理两种常见类型的代理模式,以及Spring AOP中动态代理的三种配置方式。以下是详细的知识点解析: ### 静态代理 静态代理是程序员手动创建代理类并实现相同接口的方式。代理类和...
通过本资料的学习,我们了解到Spring AOP是一种强大的工具,它通过代理机制有效地分离了业务逻辑与系统需求,极大地提升了系统的可维护性和扩展性。掌握Spring AOP的基本概念和实现方法对于开发高效、健壮的企业级...
#### 二、Spring AOP 中的动态代理实现方式 Spring AOP 使用两种主要的动态代理技术来实现面向切面编程:JDK动态代理和CGLIB代理。 ##### 1. JDK 动态代理 JDK动态代理主要用于代理那些已经实现了接口的类。...
3. **灵活的通知模型**:Spring AOP提供了多种类型的通知,包括around、before、after returning、after throwing等,使得开发者可以根据实际需求选择最适合的通知类型。 4. **丰富的切入点表达式语言**:Spring ...
1. **基于代理的AOP**:Spring提供了两种代理方式,JDK动态代理和CGLIB代理。JDK动态代理主要针对接口实现,而CGLIB代理则针对类实现。 2. **基于注解的AOP**:Spring 2.5开始支持注解驱动的AOP,通过在方法上使用`...
Spring AOP 代理一、两种代理方式1. JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。二
Spring AOP支持不同的代理策略,包括JDK动态代理和CGLIB代理。如果被代理的类没有实现接口,Spring AOP会采用CGLIB来生成代理对象。CGLIB(Code Generation Library)是一个开源的代码生成库,它允许运行时在内存中...
1. **JDK动态代理**:Spring在没有CGLIB库的情况下,会使用Java的反射API创建动态代理。动态代理类会实现目标接口,并在调用接口方法时插入通知。因此,使用JDK动态代理的目标类必须实现至少一个接口。 2. **CGLIB...
Spring AOP主要通过两种方式实现:JDK动态代理和CGLIB代理。 - **JDK动态代理**: - 当目标对象实现了至少一个接口时,Spring会使用JDK的java.lang.reflect.Proxy类创建一个代理对象。 - 代理对象在调用实际方法...
总结来说,ProxyFactoryBean是Spring AOP实现的关键组成部分,它为我们提供了创建代理对象的能力,使得我们可以灵活地在运行时增强或拦截对象的行为。通过对ProxyFactoryBean的深入理解和使用,我们可以更好地利用...
- **动态代理**:Spring AOP主要使用JDK动态代理和CGLIB实现。如果目标类实现了接口,使用JDK动态代理;否则,使用CGLIB生成子类作为代理。 - **切点(Pointcut)**:定义连接点的筛选规则,通过表达式或注解来...
1. **基于代理的AOP**:Spring使用JDK动态代理或CGLIB代理来创建代理对象。如果目标类实现了接口,Spring会使用JDK动态代理;否则,它会使用CGLIB生成一个子类来实现AOP。 2. **基于字节码增强的AOP**:通过ASM库,...
5. **配置代理**:Spring会根据目标对象是否实现了接口来决定使用JDK动态代理还是CGLIB代理。如果目标对象实现了接口,Spring会选择JDK动态代理。动态代理类会继承自`java.lang.reflect.Proxy`,并实现目标对象的...
7. **代理(Proxy)**:Spring AOP通过动态创建一个代理对象来实现对目标对象的增强。 8. **织入(Weaving)**:将切面与目标对象进行组合的过程。Spring AOP是在运行时完成织入的。 #### 三、Spring AOP 的实现机制 ...
学习这些示例,你可以更深入地理解Spring AOP的工作原理,掌握如何使用动态代理和责任链模式来编写切面,以及如何通过注解简化AOP的配置和使用。这些知识对于任何涉及Spring框架的开发者来说都是至关重要的,因为...
在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态代理。 JDK 动态代理是基于接口的,它要求被代理的目标对象必须实现至少一个接口。Spring 使用 `java.lang.reflect.Proxy`...
4. 代理的创建:Spring根据目标对象是否实现接口来决定使用JDK动态代理还是CGLIB。如果目标对象实现了接口,Spring将使用JDK动态代理;否则,使用CGLIB生成一个子类来作为代理。 5. AOP代理的使用:当通过Spring的...