public interface Waiter { void greetTo(String name); void serveTo(String name); }
public class NaiveWaiter implements Waiter { @Override public void greetTo(String name) { System.out.println("greet to "+name+"..."); } @Override public void serveTo(String name) { System.out.println("serving "+name+"..."); } }
public class GreetingBeforAdvice implements MethodBeforeAdvice { /** * method 为目标类的方法 * * args 为目标类的入参 * * obj 为目标类的实例 */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { String clientName = (String) args[0]; System.out.println("How are you! Mr " + clientName + "."); // System.out.println(target.getClass().getName()); } }
public class TestBeforAdvice { public static void main(String[] args) { Waiter target=new NaiveWaiter(); BeforeAdvice beforeAdvice=new GreetingBeforAdvice(); //spring 提供的代理工厂 ProxyFactory pf=new ProxyFactory(); //设置代理目标 pf.setTarget(target); //为代理目标添加增强 pf.addAdvice(beforeAdvice); //生成代理实例 Waiter waiter=(Waiter) pf.getProxy(); waiter.greetTo("John"); waiter.serveTo("Tom"); } }
public interface UserManagement { void addUser(String name,int age); String deleteUser(String...str); }
import com.yc.jdk.proxy.UserManagement; public class UserManagementImpl implements UserManagement { public void addUser(String name, int age) { System.out.println("add"); } public String deleteUser(String... str) { System.out.println("delete"); return "delete"; } } 3.继承jdk中的代理类InvocationHandler import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class CheckSecurity implements InvocationHandler { //声明目标类 private Object targetObject; /** * 传入要代理的对象 * * @param targetObject * @return object */ public Object CheckSecurity(Object targetObject) { this.targetObject = targetObject; return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), this.targetObject.getClass().getInterfaces(), this); } //模拟 环绕代理方法 public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { checkseiurity(); Object chckObject = null; // 获取方法名称 p("method name value ", method.getName()); // 取得此方法是不是可变参数 p("method is var args ", method.isVarArgs()); System.out.println(args.length); try { chckObject = method.invoke(this.targetObject, args); } catch (RuntimeException e) { e.printStackTrace(); } checkseiurity(); return chckObject; }
private void checkseiurity() { System.out.println("--------------check----------------"); }
public void p(Object... object) { for (int i = 0; i < object.length; i++) { System.out.print(object[i].toString()); } // 产生换行 System.out.println(); } } 4.测试jdk动态代理 import java.lang.reflect.Proxy; import com.yc.jdk.proxy.impl.UserManagementImpl; public class JdkPorxy { public static void main(String[] args) throws Exception { CheckSecurity checkSecurity = new CheckSecurity(); UserManagement management = (UserManagement) checkSecurity.CheckSecurity(new UserManagementImpl()); p(Proxy.isProxyClass(UserManagement.class)); // management.addUser("张三", 12); management.deleteUser("张三", "李四", "王五", "赵六"); } public static void p(Object object) { System.out.println(object.toString()); } }
Spring 定义了org.springframework.aop.framework.AopProxy接口,并提供了两个final类型实现类
import org.springframework.aop.BeforeAdvice; import org.springframework.aop.framework.ProxyFactory; import com.web.spring.aop.example.beforadvice.GreetingBeforAdvice; import com.web.spring.aop.example.beforadvice.NaiveWaiter; import com.web.spring.aop.example.beforadvice.Waiter; /** * @author Chris * */ public class TestProxyFactory { public static void main(String[] args) { //cglibProxyMethod(); jdkProxyMethod(); } public static void jdkProxyMethod() { Waiter target = new NaiveWaiter(); BeforeAdvice beforeAdvice = new GreetingBeforAdvice(); ProxyFactory proxyFactory = new ProxyFactory(); // 指向jdk代理 proxyFactory.setInterfaces(target.getClass().getInterfaces()); proxyFactory.setTarget(target); proxyFactory.addAdvice(beforeAdvice); create(proxyFactory); } public static void cglibProxyMethod() { Waiter target = new NaiveWaiter(); BeforeAdvice beforeAdvice = new GreetingBeforAdvice(); ProxyFactory proxyFactory = new ProxyFactory(); //强制使用cglib代理 proxyFactory.setOptimize(true); proxyFactory.setTarget(target); proxyFactory.addAdvice(beforeAdvice); create(proxyFactory); } private static void create(ProxyFactory proxyFactory) { Waiter waiter = (Waiter) proxyFactory.getProxy(); waiter.greetTo("John"); waiter.serveTo("Tom"); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <bean id="greetingAdvice" class="com.web.spring.aop.example.beforadvice.GreetingBeforAdvice"/> <bean id="target" class="com.web.spring.aop.example.beforadvice.NaiveWaiter"/> <!--ProxyFactoryBean 是FactoryBean接口的实现类 --> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.web.spring.aop.example.beforadvice.Waiter" p:interceptorNames="greetingAdvice" p:target-ref="target" p:proxyTargetClass="true" /> <!-- 1.proxyInterfaces代理所要实现的接口,可以是多个接口。该属性还有一个别名interfaces 2.interceptorNames需要织入目标对象的bean列表,采用Bean的名称指定。这些Bean必须实现了 org.aopalliance.intercept.MethodInterceptor或 org.springframework.aop.Advisor 的Bean,配置中的顺序对应调用的顺序。 3.singleton 返回的代理是否是简单实例,默认为单实例; 4.optimize 当设置成true 时,强制使用Cglib代理。 5.proxyTargetClass 是否对类进行代理(而不是对接口进行代理),设置为true时,使用CGLib代理。 --> </beans>
Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理。(建议尽量使用JDK的动态代理)
如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。
如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法)那也可以。但是需要考虑以下问题:
无法通知(advise)Final 方法,因为他们不能被覆写。
你需要将CGLIB 2二进制发行包放在classpath下面,与之相较JDK本身就提供了动态代理
强制使用CGLIB代理需要将 |aop:config| 的 proxy-target-class 属性设为true:
|aop:config proxy-target-class="true"|
...
|/aop:config|
当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 |aop:aspectj-autoproxy| 的 proxy-target-class 属性:
|aop:aspectj-autoproxy proxy-target-class="true"/|
而实际使用的过程中才会发现细节问题的差别,The devil is in the detail.JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。
CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强。
Spring是依靠什么来判断采用哪种代理策略来生成AOP代理呢?以下代码就是Spring的判断逻辑
//org.springframework.aop.framework.DefaultAopProxyFactory //参数AdvisedSupport 是Spring AOP配置相关类 public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException { //在此判断使用JDK动态代理还是CGLIB代理 if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(advisedSupport)) { if (!cglibAvailable) { thrownew AopConfigException( "Cannot proxy target class because CGLIB2 is not available. " +"Add CGLIB to the class path or specify proxy interfaces."); } return CglibProxyFactory.createCglibProxy(advisedSupport); } else { returnnew JdkDynamicAopProxy(advisedSupport); } }
advisedSupport.isOptimize()与advisedSupport.isProxyTargetClass()默认返回都是false,所以在默认情况下目标对象有没有实现接口决定着Spring采取的策略,当然可以设置advisedSupport.isOptimize()或者advisedSupport.isProxyTargetClass()返回为true,这样无论目标对象有没有实现接口Spring都会选择使用CGLIB代理。
所以在默认情况下,如果一个目标对象如果实现了接口Spring则会选择JDK动态代理策略动态的创建一个接口实现类(动态代理类)来代理目标对象,可以通俗的理解这个动态代理类是目标对象的另外一个版本,所以这两者之间在强制转换的时候会抛出java.lang.ClassCastException。而所以在默认情况下,如果目标对象没有实现任何接口,Spring会选择CGLIB代理, 其生成的动态代理对象是目标类的子类。
上说的是默认情况下,也可以手动配置一些选项使Spring采用CGLIB代理。
org.springframework.transaction.interceptor.TransactionProxyFactoryBean是org.springframework.aop.framework. ProxyConfig的子类,所以可以参照ProxyConfig里的一些设置如下所示,将optimize和proxyTargetClass任意一个设置为true都可以强制Spring采用CGLIB代理。
如果当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 |aop:aspectj-autoproxy| 的 proxy-target-class 属性:
|aop:aspectj-autoproxy proxy-target-class="true"/|
这样使用CGLIB代理也就不会出现前面提到的ClassCastException问题了,也可以在性能上有所提高,关键是对于代理对象是否继承接口可以统一使用。
两种类型AOP:静态AOP和动态AOP。
静态代理:
代理对象与被代理对象必须实现同一个接口。
demo: