很早就听说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方法进行代理。
上述代码不全,我将用到的代码类上传。
分享到:
相关推荐
Spring AOP的实现机制中文版,动态代理及原理,自定义类加载器
AOP的意思就是面向切面编程。本文主要是通过梳理JDK中自带的反射机制,实现 AOP动态代理模式,这也是Spring AOP 的实现原理
这两种代理方式在Spring AOP中起到关键作用,用于实现横切关注点的切面编程。通过学习它们的原理和实际应用,您将能够更好地理解和利用Spring AOP来提高您的应用程序的可维护性和可扩展性。 内容亮点: JDK动态...
sping AOP面向切面的编程,程序运行过程中动态加入所需代码等,对公共的问题进行集中处理,具体的实现有动态代理与静态代理,本文通过对AOP的代理机制,前置、后置、环绕、异常的通知进行了综合总结和运用!
package com.gc.aop下为:aop方式ProxyFactoryBean代理...package com.gc.javaproxy下为:java代理机制实现 package com.gc.proxy下为:自定义代理模式(面向接口编程) package com.gc.normal下为:通用日志处理方式
Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,AOP的原理就是java的动态代理机制
本文深入分析了Spring AOP的实现机制,让读者能够更好地理解和应用这一强大的编程范式。 Spring AOP是基于代理模式实现的,主要包括动态代理、通知(Advice)、切点(Pointcut)、切面(Aspect)和连接点(Join ...
Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,AOP的原理就是java的动态代理机制
何谓Spring AOP? Spring AOP 是基于 AOP 编程模式的一个框架,它的...课程从Spring AOP概念开始引入,通过Spring AOP代理和判断模式进行,宝库各种模式,不断的深入学习,相信会给同学们带来不一样的Spring AOP技术
Spring AOP主要基于动态代理模式,它允许开发者在不改变原有代码结构的情况下,增加额外的行为。这主要通过定义“切面(Aspects)”和“通知(Advices)”来实现,其中切面定义了何时以及如何插入额外的行为,而通知...
Spring AOP多种代理机制相关核心类介绍先介绍一些Spring Aop中一些核心类,大致分为三类: advisorCreator ,从spring ioc的扩展接口beanPostProcessor继承,主要用作扫描获取advisor。 advisor :顾问的意思,封装...
spring中动态代理机制的实现原理及AOP实现原理,JDK的反射,cglib类。
本文档先讲解了JDK的反射机制,然后是Proxy的动态代理、CGLIB的动态代理,因为这些是Spring AOP的底层技术,清楚了它们,你就更能够理解Spring AOP是如何工作的。在文档的最后简要写了Spring AOP的使用,因为这不是...
适用企业系统的sturts1.2+spring2.0+jdbc 的架构。 通过TransactionProxyFactoryBean 代理机制和tx/aop两种方式来管理事务的详细demo
重点掌握aop底层的原理之动态代理机制的概述及差别 1. 重点掌握代理对象执行逻辑分析 2. 重点掌握Cglib代理技术之产生代理对象和代理对象执行逻辑分析 3. 认识Spring AOP中底层常用的一些核心类 4. 源码阅读之查找...
再细问:如果循环依赖的时候,所有类又都需要Spring AOP自动代理,那Spring如何提前曝光?曝光的是原始bean还是代理后的bean? 这些问题算是Spring源码的压轴题了,如果这些问题都弄明白,恭喜你顺利结业Spring源码...
本资源利用文档加源码的方式较详细的介绍了JDK 动态代理和Spring的AOP机制.相信对您理解相关方面的知识有很大作用.
Spring提供了面向切面很好的AOP技术,用动态代理简化很多代码。设计java反射机制的一些内容,稍微有点抽象。
Spring通过@Transactional注解以及底层的AOP和代理机制实现了声明式事务。这个机制允许开发者通过简单的注解就能控制事务的边界和规则,极大地简化了编程模型。在Spring中,事务管理是通过一系列的拦截器和事务管理...
7. 重点掌握aop底层的原理之动态代理机制的概述及差别 8. 重点掌握JDK代理技术之产生代理对象和代理对象执行逻辑分析 9. 重点掌握Cglib代理技术之产生代理对象和代理对象执行逻辑分析 10. 认识Spring AOP中底层常用...