这篇文章里面就要说说Spring自己的AOP,搞清楚哪种方式是Spring自己实现的AOP,哪种方式是Spring引入aspectj的AOP。
Spring自己的AOP实现在于ProxyFactoryBean。先看下使用案例(仍和之前的案例是一样的):接口AService、实现类AServiceImpl、通知MyBeforeAdvice
public interface AService {
public void fooA(String _msg);
public void barA();
}
public class AServiceImpl implements AService{
@Override
public void fooA(String _msg) {
System.out.println("AServiceImpl.fooA(msg:"+_msg+")");
}
@Override
public void barA() {
System.out.println("AServiceImpl.barA()");
}
}
public class MyBeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("run my before advice");
}
}
然后就是xml的配置:
<bean id="aServiceImpl" class="com.lg.aop.service.impl.AServiceImpl"/>
<bean id="myBeforAdvice" class="com.lg.aop.MyBeforeAdvice"/>
<bean class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.lg.aop.service.AService"/>
<property name="target">
<ref bean="aServiceImpl"/>
</property>
<property name="interceptorNames">
<list>
<value>myBeforAdvice</value>
</list>
</property>
</bean>
然后就可以使用了:
@Autowired
private AService aService;
@Test
public void testAOP(){
aService.barA();
}
运行这个单元测试,然后你就会看到报如下错误:
No qualifying bean of type [com.lg.aop.service.AService] is defined: expected single matching bean but found 2: aServiceImpl,org.springframework.aop.framework.ProxyFactoryBean#0
原因就是对于接口AService,有两个实现类aServiceImpl和ProxyFactoryBean所生产的代理类。所以我们不能使用@Autowired(它是按类型注入),所以要使用按名称注入,我们怎么获取ProxyFactoryBean所产生的代理类的名称呢?其实就是ProxyFactoryBean配置的名称。因为ProxyFactoryBean实现了FactoryBean接口,对于这种接口从容器中获取该bean,不是获取的本身而是获取他的getObject方法所返回的值,看FactoryBean的文档:
/**
* Interface to be implemented by objects used within a {@link BeanFactory}
* which are themselves factories. If a bean implements this interface,
* it is used as a factory for an object to expose, not directly as a bean
* instance that will be exposed itself.
*
* <p><b>NB: A bean that implements this interface cannot be used as a
* normal bean.</b> A FactoryBean is defined in a bean style, but the
* object exposed for bean references ({@link #getObject()} is always
* the object that it creates.
所以通过beanName找到了ProxyFactoryBean,然而不是返回该对象,而是返回他的getObject方法的返回值,所以我们通过ProxyFactoryBean的id就可以获取到它所产生的代理对象,所以更改如下:
<bean id="aServiceImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
其他略
在使用注入的时候按名称注入
@Resource(name="aServiceImplProxy")
private AService aService;
然后就可以正常运行了如下:
run my before advice
AServiceImpl.barA()
然后我们就要源码分析下这一过程,先看下是如何产生代理对象的,在ProxyFactoryBean的getObject方法中:
public Object getObject() throws BeansException {
//重点1
initializeAdvisorChain();
if (isSingleton()) {
//重点2
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
重点1:就是根据我们配置的interceptorNames来获取对应的bean,并却转化成Advisor。如下:
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
if (this.advisorChainInitialized) {
return;
}
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
}
}
}
this.advisorChainInitialized = true;
}
this.advisorChainInitialized:标示是否已进行过初始化,若以初始化则不再进行初始化。然后就是将interceptorNames转化成Advisor。根据interceptorNames所包含的字符串到容器中进行查找,如果含有*则,则表示进行一定的匹配,符合的都会纳入。如官方文档中说的:
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="service"/>
<property name="interceptorNames">
<list>
<value>global*</value>
</list>
</property>
</bean>
<bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>
这中间页经过了Advice到Advisor的转换,如下:
private void addAdvisorOnChainCreation(Object next, String name) {
// We need to convert to an Advisor if necessary so that our source reference
// matches what we find from superclass interceptors.
Advisor advisor = namedBeanToAdvisor(next);
if (logger.isTraceEnabled()) {
logger.trace("Adding advisor with name '" + name + "'");
}
addAdvisor(advisor);
}
private Advisor namedBeanToAdvisor(Object next) {
try {
return this.advisorAdapterRegistry.wrap(next);
}
}
}
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
这个包裹过程已经见过很多遍了,采用了适配器的模式。
之后又是和其他的AOP方式接轨了,设置一些列要实现的接口和参数,使用DefaultAopProxyFactory先创建出AopProxy,要么是JdkDynamicAopProxy,要么是CglibAopProxy,然后就可以调用AopProxy的getProxy方法来获取代理对象了。这个过程详见上一篇博客http://lgbolgger.iteye.com/blog/2119810。
这种方式实现的AOP还是比较麻烦的,同时配置一个ProxyFactoryBean仅能实现对一个目标对象的拦截,要想拦截多个目标对象,需要配置多个ProxyFactoryBean。所以大部分还是使用Spring引进的aspectj的AOP方式来进行AOP编程。
若想转载请注明出处: http://lgbolgger.iteye.com/blog/2122993
作者:iteye的乒乓狂魔
分享到:
相关推荐
《Spring AOP 源码分析》 在深入探讨Spring AOP之前,我们先要理解AOP(面向切面编程)的基本概念。AOP是一种编程范式,它将关注点分离,使得我们可以将横切关注点(如日志、事务管理、安全检查等)与业务逻辑解耦...
5. **源码分析**: 在`ProxyFactoryBean`的`getObject()`方法中,会调用`createAopProxy()`生成`AopProxy`,然后`AopProxy`的`getProxy()`方法返回实际的代理对象。`createAopProxy()`会根据配置判断使用JDK还是...
《深入剖析Spring AOP源码》 Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对现有代码进行功能增强的技术。本文将深入探讨Spring ...
**Spring AOP介绍** ...学习并掌握Spring AOP及其源码分析对于提升作为IT专业人员的技术水平至关重要,它不仅能够帮助我们编写更加优雅和简洁的代码,还能使我们更好地应对复杂的企业级应用需求。
- `org.springframework.aop.framework.ProxyFactoryBean` 和 `org.springframework.aop.framework.JdkDynamicAopProxy` 是动态代理的关键类。 - `org.springframework.aop.aspectj.AspectJExpressionPointcut` ...
深入研究Spring AOP的源码,可以帮助我们更好地理解其工作原理,例如,可以查看`org.springframework.aop.framework.ProxyFactoryBean`、`org.springframework.aop.aspectj.autoproxy.AspectJProxyFactoryBean`、`...
本文将围绕Spring AOP的源码分析,探讨其核心概念、工作原理以及在实际开发中的应用。 一、AOP核心概念 1. 切面(Aspect):切面是关注点的模块化,通常包含一组通知(advises)和一个切入点(pointcut)定义。 2...
标题中的“spring-aop”指的是Spring框架中的面向切面编程(Aspect-Oriented Programming, AOP)模块,它...而阅读博主分享的源码分析和实践技巧,可以帮助我们更深入地理解这一技术,并将其有效地应用于实际项目中。
#### 五、Spring AOP 的源码分析 Spring AOP的核心在于`Advisor`和`Advice`的实现,这些类通过`ProxyFactoryBean`或`CglibAopProxy`等代理工厂类生成代理对象。 1. **`Advisor`**:封装了`Pointcut`和`Advice`,是...
6. **源码分析**:对于深入理解Spring AOP,阅读其源码是非常有帮助的。你可以通过查看`org.springframework.aop.framework.ProxyFactoryBean`和`org.springframework.aop.aspectj.annotation....
《Spring AOP 深入理解与应用》 ...为了更好地理解Spring AOP的工作机制,可以阅读Spring AOP的源码,例如`org.springframework.aop.framework.ProxyFactoryBean`和`org.springframework.aop.aspectj.annotation....
标签 "源码" 和 "工具" 提示我们,这篇文档可能不仅涉及Spring AOP的基本概念和使用,还可能探讨其内部实现原理,比如源代码分析,以及可能介绍一些辅助开发和理解AOP的工具,如AspectJ weaving tool 或者其他的日志...
Spring AOP的源码分析主要涉及以下几个部分: - **ProxyFactoryBean**:它是Spring AOP代理的工厂类,负责创建代理对象。 - **Advised**:接口,代表可以配置通知的对象,如代理对象。 - **AopProxy**:接口,定义了...
在源码分析的过程中,读者会深入理解Spring的内部工作机制,例如如何解析配置、如何创建bean实例、如何实现AOP代理等。这将有助于开发者编写更高效、更健壮的代码,也能为参与Spring的扩展或定制打下坚实基础。 总...
第三部分深入探讨了Spring框架的内部结构、设计原理以及项目源码分析。最后一部分则探讨了开源领域的相关话题,如开源框架设计的思考、开源社区的互动等。 本书还指出,通过EasyJF开源交流社区的论坛和SVN仓库可以...
控制反转)、AOP(Aspect Oriented Programming,面向切面编程)以及Transaction(事务管理)的源码分析,帮助开发者更全面地理解Spring的工作机制。 首先,让我们深入探讨Spring的IoC容器。IoC是Spring的核心特性...
通过阅读和分析Spring 1.2.6的源码,不仅可以学习到Spring的核心设计原则,还能了解到设计模式的运用,例如工厂模式、单例模式、观察者模式等。同时,这也是提升Java编程技巧和理解框架底层运作的好机会。在实际的...
Spring AOP的实现主要涉及到`org.springframework.aop.framework.ProxyFactoryBean`、`org.springframework.aop.framework.DefaultAopProxyFactory`、`org.springframework.aop.aspectj.AspectJExpressionPointcut`...
《Spring源码分析》 Spring框架作为Java领域中不可或缺的一部分,其强大之处在于它提供了丰富的功能,包括依赖注入(Dependency Injection,简称DI)、面向切面编程(Aspect-Oriented Programming,简称AOP)、事务...
本文将深入Spring源码,探索AOP的实现原理。 首先,我们需要理解AOP的基本概念。AOP允许开发者定义“切面”(Aspect),一个切面封装了跨越多个对象的横切关注点。切点(Pointcut)定义了这些关注点在何时何地被...