Aspect Oriented Programming(AOP),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
有两种方式可以实现aop,一种是根据利用jdk自带的proxy,另外一种是利用cglib的proxy.
一 jdk代理
JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中 InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。
自定义一个接口
public interface TestInterface {
public void insert();
}
实现接口
public class TestImpl implements TestInterface{
@Override
public void insert() {
// TODO Auto-generated method stub
System.out.println("插入数据");
}
}
创建jdk动态代理的工厂类
public class JdkDymanicProxyFactory implements InvocationHandler{
private Object targetObject;
public Object createProxyFactory(Object target){
this.targetObject = target;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
//执行方法的时候回去回调这个函数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
//在这里做一下日记
System.out.println("execute:"+method.getName());
return method.invoke(targetObject, args);
}
}
测试执行结果
package com.lwq;
/**
* @author thomaslwq
* @version 创建时间:Sep 17, 2012 8:56:20 AM
* 类说明 利用jdk的动态代理实现aop
*/
public class JdkProxyTest {
public static void main(String args[]){
JdkDymanicProxyFactory jdpf = new JdkDymanicProxyFactory();
TestInterface ti = (TestInterface) jdpf.createProxyFactory(new TestImpl());
ti.insert();
}
}
运行结果如下:
execute:insert
插入数据
二 利用cglib代理实现aop
CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。 CGLIB是针对类实现代理的,主要对指定的类生成一个子类,并覆盖其中的方法, 因为是继承,所以不能使用final来修饰类或方法 。和jdk代理实现不同的是,cglib不要求类实现接口。
即你可以直接编出一个类:
public class CglibTestImpl {
public void insert() {
// TODO Auto-generated method stub
System.out.println("插入数据");
}
}
然后创建cglib代理的工厂类:
package com.lwq;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* @author thomaslwq
* @version 创建时间:Sep 17, 2012 9:24:23 AM
* 类说明
*/
public class CglibProxyFactory implements MethodInterceptor{
private Object targetObject;
public Object createProxyInstance(Object target){
this.targetObject = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.targetObject.getClass());
//设置回调函数
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
// TODO Auto-generated method stub
System.out.println("record:"+method.getName());
System.out.println("Object:"+obj.getClass());
System.out.println("targetObject:"+targetObject.getClass());
return method.invoke(targetObject, args);
}
}
最后写一个测试类:
package com.lwq;
/**
* @author thomaslwq
* @version 创建时间:Sep 17, 2012 9:29:21 AM
* 类说明
*/
public class CglibProxyTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
CglibProxyFactory cpf = new CglibProxyFactory();
//没有实现接口
CglibTestImpl ti = (CglibTestImpl)cpf.createProxyInstance(new CglibTestImpl());
ti.insert();
}
}
测试结果如下:
record:insert
插入数据
JDK动态代理和CGLIB字节码生成的区别?
* JDK动态代理只能对实现了接口的类生成代理,而不能针对类
* CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final
SPRING是通过动态代理来实现AOP的,SPRING内部提供了2种实现机制
1.如果是有接口声明的类进行AOP,spring调用的是java.lang.reflection.Proxy类来做处理
org.springframework.aop.framework.JdkDynamicAopProxy
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
Class targetClass = this.advised.getTargetSource().getTargetClass();
logger.debug(“Creating JDK dynamic proxy” +
(targetClass != null ? ” for [" + targetClass.getName() + "]” : “”));
}
Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
org.springframework.aop.framework.ReflectiveMethodInvocation
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() – 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It’s an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
2.如果是没有接口声明的类呢?SPRING通过CGLIB包和内部类来实现
private static class StaticUnadvisedInterceptor implements MethodInterceptor, Serializable {
private final Object target;
public StaticUnadvisedInterceptor(Object target) {
this.target = target;
}
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
Object retVal = methodProxy.invoke(target, args);
return massageReturnTypeIfNecessary(proxy, target, retVal);
}
}
/**
* Method interceptor used for static targets with no advice chain, when the
* proxy is to be exposed.
*/
private static class StaticUnadvisedExposedInterceptor implements MethodInterceptor, Serializable {
private final Object target;
public StaticUnadvisedExposedInterceptor(Object target) {
this.target = target;
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
try {
oldProxy = AopContext.setCurrentProxy(proxy);
Object retVal = methodProxy.invoke(target, args);
return massageReturnTypeIfNecessary(proxy, target, retVal);
}
finally {
AopContext.setCurrentProxy(oldProxy);
}
}
}
/**
* Interceptor used to invoke a dynamic target without creating a method
* invocation or evaluating an advice chain. (We know there was no advice
* for this method.)
*/
private class DynamicUnadvisedInterceptor implements MethodInterceptor, Serializable {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object target = advised.getTargetSource().getTarget();
try {
Object retVal = methodProxy.invoke(target, args);
return massageReturnTypeIfNecessary(proxy, target, retVal);
}
finally {
advised.getTargetSource().releaseTarget(target);
}
}
}
/**
* Interceptor for unadvised dynamic targets when the proxy needs exposing.
*/
private class DynamicUnadvisedExposedInterceptor implements MethodInterceptor, Serializable {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
Object target = advised.getTargetSource().getTarget();
try {
oldProxy = AopContext.setCurrentProxy(proxy);
Object retVal = methodProxy.invoke(target, args);
return massageReturnTypeIfNecessary(proxy, target, retVal);
}
finally {
AopContext.setCurrentProxy(oldProxy);
advised.getTargetSource().releaseTarget(target);
}
}
}
我们自己也可以来试试
1.jdk proxy方式
先来一个接口
IHelloWorld.java
package kris.aop.test;
public interface IHelloWorld {
public void print(String name);
public void write(String sth);
}
再来一个实现
HelloWorld.java
package kris.aop.test;
public class HelloWorld implements IHelloWorld {
public void print(String name){
System.out.println(“HelloWorld “+name);
}
public void write(String sth) {
System.out.println(“write “+sth);
}
}
代理类
DefaultInvocationHandler.java
package kris.aop.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DefaultInvocationHandler implements InvocationHandler {
/**
* 替换外部class调用的方法
* obj 外部已经已经包装好InvocationHandler的实例
* method 外部方法
* args 方法参数
*/
public Object invoke(Object obj, Method method, Object[] args)
throws Throwable {
String s1 []={“kris”};
String s2 []={“anyone”};
IHelloWorld ihw=new HelloWorld();
System.out.println(“start!”);
method.invoke(ihw,args);
method.invoke(ihw,s1);
Object o=method.invoke(ihw,s2);
System.out.println(“stop!”);
return o;
}
}
测试类
Test.java
package kris.aop.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String args []){
Class clazz = new HelloWorld().getClass();
ClassLoader cl = clazz.getClassLoader();
Class classes [] = clazz.getInterfaces();
InvocationHandler ih=new DefaultInvocationHandler();
//用InvocationHandler给HelloWorld进行AOP包装
IHelloWorld ihw=(IHelloWorld) Proxy.newProxyInstance(cl,classes,ih);
ihw.print(“test”);
ihw.write(“test”);
}
}
2.用CGLIB包实现,首先不要忘了引入那个包
package kris.aop.cglib.test;
public class HelloWorld {
public void print(String name){
System.out.println(“HelloWorld “+name);
}
public void write(String sth) {
System.out.println(“write “+sth);
}
public void print(){
System.out.println(“HelloWorld”);
}
}
代理类(没用内部类,看起来清楚点)
package kris.aop.cglib.test;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class MethodInterceptorImpl implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println(method);
proxy.invokeSuper(obj, args);
return null;
}
}
测试类
package kris.aop.cglib.test;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HelloWorld.class);
//设置回调方法实现类
enhancer.setCallback(new MethodInterceptorImpl());
//实例化已经添加回调实现的HELLOWORLD实例
HelloWorld my = (HelloWorld) enhancer.create();
my.print();
}
}