`
lucky520
  • 浏览: 35787 次
  • 性别: Icon_minigender_2
  • 来自: 武汉
社区版块
存档分类
最新评论

Spring AOP之代理机制

阅读更多

    很早就听说spring aop,一直没有静下来学习,今天看了下《精通spring》,将我理解的spring aop做下笔记。当然,首先还是什么是AOP呢?AOP(Aspect Oriented Programming)面向方面编程,但对于spring来说理解为“面向方面编程”更确切。那么又是为什么要用AOP呢?大家都知道OOP(Oriented Object Programming)面向对象编程,主要特点是封装,继承,多态。这里主要想说一下继承,如果多个类具有相同的属性或方法,我们则考虑定义一个父类。然后让其子类继承。比如:定义一个Animal具有run(),eat()两个抽象方法的父类,然后让rabbit,horse继承Animal类重写run(),

eat(),通过引用父类来消除重复代码。说了这么多就是为了引入spring aop,下面来看一段大家都属性的代码:

package com.me.services.imp;

import com.me.entity.User;
import com.me.services.UserService;
import com.me.daos.UserDAO;
import com.me.util.TransationManager;
import com.me.util.PerformanceMonitor;

public class UserServiceImp implements UserService {
    private TransationManager trans = new TransationManager();
    private PerformanceMonitor pmonitor = new PerformanceMonitor();
    private UserDAO userDao = new UserDAO();
    
	public void deleteUser(int userId) {
		pmonitor.start("com.me.services.imp.UserServiceImp.deleteUser");//1
		trans.beginTransation();//2
		userDao.deleteUser(userId);
		trans.commitTransation();
		pmonitor.end();
	}

	public void insertUser(User user) {
		pmonitor.start("com.me.services.imp.UserServiceImp.insertUser");//1
		trans.beginTransation();//2
		userDao.inserUser(user);
		trans.commitTransation();
		pmonitor.end();
	}

}

这段代码就是用于监控添加用户和删除用户的性能,除了业务逻辑外,大量的事务处理和性能监控重复代码(1、2代码),

那能不能也抽象一个父类,当然不行,因为继承是纵向抽取机制,这里就是用到AOP横向切割的方式抽取一个独立的模块。

总结:AOP运用场合有,性能监控,访问控制,事务处理,日志记录。

 

学习Spring AOP,大家要先掌握几个AOP相关的重要术语。下面是我的理解,如有异议,大家可以相互讨论一下。

连接点(Joinpoint):程序的执行点。如:类初始化之前、后,方法调用之前、后等。

切点(Pointcut):定位某个方法,通过org.springframework.aop.Pointcut接口描述。

增加(Advice):织入到目标类连接点上的一段代码。spring提供了前置增强,后置增强,异常增强,环绕增强四种类型。

目标对象(target):业务逻辑类.

引介(Introduction):一种特殊的增强,能动态的为业务类添加一个实现接口。让业务类实现该接口。

织入(Weaving):将增强添加到目标类的一个过程。分为编译期织入,类装载期织入,动态代理织入。spring采用的就是动态代理织入,因为前两种需要特殊的java编译器和类装载器。

代理(Proxy):融合了业务逻辑类和增强的代理类。

切面(Aspect):有切点与增强组成。将在后面说到。

 

上面说到spring aop采用的是动态代理的方式织入的,那么什么是动态代理织入呢?就是在运行期为目标类添加增强生成子类的方式。那么动态代理又分为那些呢?JDK动态代理(通过接口创建代理),CGLib动态代理(通过类创建代理)。

 

JDK动态代理主要运用java.lang.reflect包中的Proxy类和InvocationHandle接口.通过实现InvocationHandle接口定义横切逻辑,并通过反射机制调用目标类中的代码(如果你对反射机制,可参看我博客反射机制的讲解),动态的将业务逻辑和横切逻辑编织在一起。而Proxy则用于生成一个目标类的代理对象。下面来看一段代码:

将代码一处1、2代码部分去掉

	public void deleteUser(int userId) {
		//pmonitor.start("com.me.services.imp.UserServiceImp.deleteUser");
		//trans.beginTransation();
		userDao.deleteUser(userId);
		//trans.commitTransation();
		//pmonitor.end();
	}

	public void insertUser(User user) {
		//pmonitor.start("com.me.services.imp.UserServiceImp.insertUser");
		//trans.beginTransation();
		userDao.inserUser(user);
		//trans.commitTransation();
		//pmonitor.end();
	}

 

居然JDK动态代理是通过接口创建代理,那么我们就定义个实现InvocationHandle接口,完成业务代码与横切代码编织创建代理实例。

package com.me.util;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PerformanceHandler implements InvocationHandler {

	private Object target;
	
	public PerformanceHandler(Object target){
		this.target = target;
	}
	/**
	 * @param proxy 最终生成的代理实例,一般不会用到
	 * @param method 业务代理中某个具体方法,发起目标实例方法的反射调用
	 * @param args 业务代理中方法的参数,在方法反射时调用
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//自定义的一个性能监控类
		PerformanceMonitor pMonitor = new PerformanceMonitor();
		//传入一个性能监控的方法的全限名,即包名+类名+方法名
		pMonitor.start(target.getClass().getName()+"."+method.getName());
		//通过反射方法调用业务类的目标业务,返回一个业务代理
		Object obj = method.invoke(target,args);
		pMonitor.end();
		return obj;
	}

}

 

编写测试类:

package com.me.test;

import com.me.entity.User;
import com.me.services.UserService;
import com.me.services.imp.UserServiceImp;
import com.me.util.PerformanceHandler;
import java.lang.reflect.Proxy;

public class TestUserService {
 
	public static void main(String[] args) {
        //通过JDK创建代理类实例
		UserService target = new UserServiceImp();//希望被代理的业务类
		PerformanceHandler handler = new PerformanceHandler(target);
		//根据业务逻辑类和实现InvocationHandler接口性能横切逻辑创建代理实例
		UserService proxy = (UserService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
		//参数一:类加载器 参数二:创建代理实例需要的接口 参数三:业务逻辑与横切逻辑编程器对象
		proxy.deleteUser(1);
		User user = new User();
		proxy.insertUser(user);
	}

 我们知道JDK动态代理是通过接口定义业务方法类的,那么不用接口定义业务类,我们就要用到CGLib动态创建代理了。

CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截父类方法的调用,并顺势织入横切逻辑。下面来看段代码:

package com.me.util;

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 CglibProxy implements MethodInterceptor {
	//这里引入一个enhancer,查了一下,它的原理就是用Enhancer生成一个原有类的子类,并且设置好callback到proxy, 则原有类的每个方法调用都会转为调用实现了MethodInterceptor接口的proxy的intercept() 函数
    private Enhancer enhancer = new Enhancer();
    
    @SuppressWarnings("unchecked")
	public Object getProxy(Class clazz){
    	enhancer.setSuperclass(clazz);
    	enhancer.setCallback(this);
    	return enhancer.create();
    }
	public Object intercept(Object target, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		PerformanceMonitor pm = new PerformanceMonitor();
		pm.start(target.getClass().getName()+"."+method.getName());
		//通过代理类调用父类中的方法
		Object obj = proxy.invokeSuper(target,args);
		pm.end();
		return obj;
	}

}

 测试cglib创建动态代理

package com.me.test;

import com.me.entity.User;
import com.me.services.UserService;
import com.me.services.imp.UserServiceImp;
import com.me.util.CglibProxy;

public class TestUserService {
 
	public static void main(String[] args) {
		//cglib创建代理实例
		CglibProxy proxy = new CglibProxy();
		UserService service = (UserServiceImp)proxy.getProxy(UserServiceImp.class);
		service.deleteUser(1);
		service.insertUser(new User());
	}
}

 

在控制台输出我们可以看到"$$EnhancerByCGLIB$$e28373d6"这是cglib动态创建的子类。

 

那么两种动态代理要怎么取舍呢?

cglib比jdk创建动态代理的性能高大约10倍,但是cglib在创建代理对象时间比jdk多8倍。因此,对于创建singleton或实例池对象代理用cglib方式比较合适,因为无须频繁创建代理对象,但由于cglib采用动态创建子类的方式生成代理对象,所以对目标类中的final方法进行代理。

 

上述代码不全,我将用到的代码类上传。

 

 

 

 

 

 

 

 

分享到:
评论
3 楼 lucky520 2008-11-05  
Joo 写道

引用
cglib比jdk创建动态代理的性能高大约10倍,但是cglib在创建代理对象时间比jdk多8倍。因此,对于创建singleton或实例池对象代理用cglib方式比较合适,因为无须频繁创建代理对象,但由于cglib采用动态创建子类的方式生成代理对象,所以对目标类中的final方法进行代理。不知道这个结论是不是经过测试得到的,我现在基本上都是用CGLIB生成代理,而实际情况是需要频繁用CGLIB生成代理对象来调用其上的方法,更重要的是没有接口可实现...-_-|||

可以自己写个示例测试一下,最近在学习spring,这个结论是我从书上看到的。
2 楼 Joo 2008-11-03  
引用
cglib比jdk创建动态代理的性能高大约10倍,但是cglib在创建代理对象时间比jdk多8倍。因此,对于创建singleton或实例池对象代理用cglib方式比较合适,因为无须频繁创建代理对象,但由于cglib采用动态创建子类的方式生成代理对象,所以对目标类中的final方法进行代理。


不知道这个结论是不是经过测试得到的,我现在基本上都是用CGLIB生成代理,而实际情况是需要频繁用CGLIB生成代理对象来调用其上的方法,更重要的是没有接口可实现...-_-|||
1 楼 278506470 2008-10-26  
Spring之新技术又出炉了,我都没有时间研究了,自己都没有心思去做,去看,又把博客给丢到一边了。
坚持啊!
哈哈

相关推荐

    Spring AOP实现机制

    Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的可复用性和可维护性。 ### 1. ...

    spring之AOP(动态代理)

    总结一下,Spring的AOP机制通过JDK动态代理和CGLIB动态代理提供了强大的横切关注点管理功能。开发者可以轻松地定义切面和通知,以实现如日志、事务管理等功能,同时保持核心业务代码的清晰和简洁。在Spring Boot项目...

    反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    在Java开发中,反射机制是实现动态代理的关键技术之一。反射提供了在运行时访问和操作类的能力,这使得动态代理的实现成为可能。在Java中,可以使用java.lang.reflect包下的相关类和接口实现动态代理。 例如,通过...

    springAop默认代理方式.zip

    当目标对象实现了至少一个接口时,Spring将使用JDK的动态代理机制。JDK动态代理通过实现InvocationHandler接口,并在运行时动态生成一个实现了目标对象所有接口的代理类。 - **JDK动态代理**:JDK的java.lang....

    Spring AOP 16道面试题及答案.docx

    Spring AOP代理是框架为实现切面功能创建的对象,它在运行时实现切面协议。Spring提供了两种代理方式:JDK动态代理和CGLIB代理。JDK代理适用于那些实现了接口的类,而CGLIB代理则适用于没有实现接口的类。 引介...

    springAOP配置动态代理实现

    综上所述,通过理解Spring AOP的配置和动态代理机制,我们可以灵活地在项目中添加横切关注点,提升代码的模块化和可维护性。在实际开发中,结合使用XML配置、注解配置以及适当的动态代理策略,可以使AOP功能更好地...

    Spring框架+SpringAOP动态代理

    ### Spring框架+SpringAOP动态代理 #### 一、Spring AOP 动态代理概述 在探讨Spring AOP(Aspect-Oriented Programming,面向切面编程)中的动态代理之前,我们首先简要回顾一下AOP的基本概念。面向切面编程是一种...

    spring AOP代理机制.docx

    总之,Spring AOP通过代理机制和通知机制,为开发者提供了一种优雅的方式,来处理那些横切关注点,提高了代码的复用性和模块化,降低了系统复杂性,使得业务逻辑更加清晰,提高了开发效率。无论是静态代理还是动态...

    SpringAOP之探秘(动态代理、责任链模式、注解使用)

    CGLIB通常作为Spring AOP的默认代理机制,因为它可以处理未实现接口的类。 接下来,我们来探讨责任链模式。在Spring AOP中,每个切面(Aspect)都可以看作是责任链上的一个节点。当一个方法被调用时,这个调用会...

    spring aop依赖jar包

    最常见的是运行时织入,通过Spring的代理机制实现。 现在,我们回到主题——"springaop依赖的jar包"。在Spring 2.5.6版本中,使用Spring AOP通常需要以下核心jar包: - `spring-aop.jar`:这是Spring AOP的核心库...

    springAOP之代理模式.docx

    【Spring AOP与代理模式】 Spring AOP,即Spring中的面向切面编程,是一种用于解决传统面向对象编程(OOP)中代码冗余问题的技术。在OOP中,常见的如日志记录、权限验证等功能往往需要在每个业务方法中重复编写,...

    Java动态代理(Spring Aop原理)

    动态代理提供了创建代理对象的机制,而Spring AOP则是基于动态代理实现的面向切面编程框架,简化了在多处插入相同逻辑的复杂度。在实际开发中,理解并熟练运用这两个技术对于提高代码质量和可维护性至关重要。

    反射实现 AOP 动态代理模式(Spring AOP 的实现 原理) - Java 例子 -

    Spring框架是Java中实现AOP的一个流行工具,它通过动态代理机制实现了这一功能。本文将深入探讨Spring AOP的实现原理,以及如何使用反射来实现动态代理模式。 首先,我们需要了解AOP的基本概念。AOP的核心思想是切...

    Spring Aop四个依赖的Jar包

    总的来说,Spring AOP通过这四个关键的Jar包,结合AspectJ的强大功能和CGLIB的代理机制,为开发者提供了强大的面向切面编程支持,使得我们可以在不侵入原有业务代码的情况下,实现跨切面的关注点管理。

    Spring AOP面向方面编程原理:AOP概念

    7. **AOP代理(AOP Proxy)**:由AOP框架创建的对象,用于包含通知逻辑。Spring提供了两种类型的代理:JDK动态代理和CGLIB代理。 8. **编织(Weaving)**:是指将通知插入到目标对象的过程。Spring AOP是在运行时...

    JDK动态代理 spring aop 的原理

    5. AOP代理的使用:当通过Spring的依赖注入(DI)获取到一个对象时,实际上得到的是一个代理对象。通过这个代理对象调用方法,Spring会自动插入预先定义好的通知逻辑。 总的来说,JDK动态代理是Spring AOP实现的...

    spring-aop实例

    5. **代理(Proxy)**:Spring AOP通过动态代理机制创建目标对象的代理,代理对象负责拦截方法调用并执行通知。有两种代理类型:JDK动态代理和CGLIB代理。JDK代理用于实现了接口的目标对象,而CGLIB代理则用于没有...

    spring aop spring aop

    5. **代理(Proxy)**:Spring AOP通过动态代理机制创建目标对象的代理,代理对象在调用目标方法时会自动插入切面逻辑。在Java项目中,Spring可以使用JDK动态代理或CGLIB动态代理来创建代理对象。 在实际应用中,...

    spring AOP依赖三个jar包

    Spring AOP和其他AOP框架(如AspectJ)都实现了这些接口,以实现方法拦截和通知机制。 2. aspectjweaver-1.7.0.jar:这是AspectJ的织入器,负责在运行时动态地将切面(aspect)织入到目标类中。AspectJ提供了一种...

    spring AOP的运用

    3. Spring AOP的代理机制分为JDK动态代理和CGLIB代理。如果目标类实现了接口,Spring会选择JDK动态代理;否则,使用CGLIB生成子类进行代理。 4. 通知的执行顺序可以通过`@Order`注解或`@Priority`注解来控制。Spring...

Global site tag (gtag.js) - Google Analytics