什么是aop?
aop(Aspect Oriented Programming)面向切面编程。是oop面向对象思想的一种补充和延续。也是Spring框架的一种重要的组件!
Spring中Aop代理是由SpringIOC容器负责生成、管理,其依赖关系也是由IOC容器负责处理的。
在Spring中,默认情况下是使用java动态代理技术来实现
当需要代理的类不是接口类型的时候,Spring会自动切换为CGLIB来进行代理,也可以强制的选择使用CGLIB来进行代理
可以看一下SpringAOP的源代码
package org.springframework.aop.framework; import java.io.Serializable; import java.lang.reflect.Proxy; import org.springframework.aop.SpringProxy; @SuppressWarnings("serial") public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override
//创建Aop代理 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//判断配置是否有效,配置中有代理类信息,判断有没有用户自己定义的解析接口 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); }
//如果是接口,或者Proxy的类,返回默认的JDK动态代理对象 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); }
//配置中有用户自己指定的代理信息,则使用cglib进行代理 return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]))); } }
首先从通过配置信息解析有没有指定的解析方法。
如果配置信息中没有的话,就使用默认的JdkDynamicAopProxy()来进行代理
好了,现在知道了Spring在什么情况下使用什么代理。下面开始深入了解一下jdk代理和cglib代理吧
动态代理是jdk1.5引进的新的技术。动态代理的类位于Java.lang.reflect包下
先举个栗子!
BookStore.java
public interface BookStore { public void addBook(); public void deleteBook(); }
还有一个实现该接口的实现类
BookStoreImpl.java
package test; public class BookStoreImpl implements BookStore { public void addBook() { System.out.println("增加图书方法。。。"); } public void deleteBook() { System.out.println("我現在要刪除一個書"); } }
BookStoreProxy.java
package test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class BookStoreProxy implements InvocationHandler { private Object target; public Object bind(Object target) { this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("代理事务开始啦"); result = method.invoke(target, args); System.out.println("代理事务结束啦"); return result; } }
测试一下
package test; public class TestProxy { public static void main(String[] args) { BookStoreProxy proxy = new BookStoreProxy(); BookStore bs = (BookStore) proxy.bind(new BookStoreImpl()); bs.addBook(); System.out.println("-------------------"); bs.deleteBook(); } }
输出结果
代理事务开始啦 增加图书方法。。。 代理事务结束啦 ------------------- 代理事务开始啦 我現在要刪除一個書 代理事务结束啦
从测试的过程中可以看到,我们没有改变原来的那个BookStore接口和BookStoreImpl实现类。
但是实现了方法的注入
这就是动态代理了,它的作用有以下几点
1.Proxy类的代码量可以降下来,不会因为业务的增大而庞大起来
2.可以实现aop编程,虽然静态代理也可以实现
3.降低耦合性,通过参数就可以判断真实的类,不需要事先实例化,比较灵活
jdk代理很好啊,但是仔细想一下还是有缺陷啊,Proxy类只能代理接口类
所以cglib(Code generation Library)就出现了,完美的拓展了proxy的性能,它可以代理接口的和类。碉堡了
再举个栗子!
action.java
package cglib.test; public class Action { public void playGame(){ System.out.println("上班玩游戏..."); } public void smoke(){ System.out.println("上班抽烟..."); } }
ActionFactory.java
package cglib.test; public class ActionFactory { public static Action action = new Action(); public static Action getActionInstance(){ return action; } }
ActionTest.java
package cglib.test; import org.junit.Before; import org.junit.Test; public class ActionTest { @Before public void setUp() throws Exception { } @Test public void test() { Action action = ActionFactory.getActionInstance(); action.playGame(); action.smoke(); } }
好了,运行没有问题。playGame和smoke两个动作可以完成,但是新的需求来了
老板说,只有他能在上班的时候玩游戏!之前的类不能动!
用jdk中的动态代理当然可以实现,但是我们这没有Action的接口。要是使用jdk动态代理的话,我们还需要创建新的接口!老板说了不能动原来的类。
所以我们选用cglib
再搞一个
ActionCglibProxy.java
package cglib.test; 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 ActionCglibProxy implements MethodInterceptor { private String name; private Enhancer enhancer = new Enhancer(); public ActionCglibProxy(String name) { super(); this.name = name; } public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { if ("zhyonk".equals(name)) { Object result = proxy.invokeSuper(obj, args); return result; } System.out.println(name + "你不可以抽烟哦"); return null; } public Action getAction(){ enhancer.setSuperclass(Action.class); enhancer.setCallback(this); return (Action) enhancer.create(); } }
测试一下
@Test public void TestCglibAction() { ActionCglibProxy proxy = new ActionCglibProxy("老板"); Action action = proxy.getAction(); action.playGame(); action.smoke(); }
成功代理了,这个过程中没有用到接口。
通过Enhancer进行对类的注入。
getAction()返回的是原有的被代理类Action的子类
暂时就是这样啦!