原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主
代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
动态代理实现主要有2种形式,主要分为:
1.jdk动态代理:
1)原理:是根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口 面向接口生成代理,位于java.lang.reflect包下)
2)实现方式:
1. 通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
2~4步骤可合并
package proxy.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.junit.Test; public class JDKProxy{ //写法1 private Object targetObject;//代理目标 public Object CustomerProxy(Object obj) { targetObject = obj; return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(),new targetHandler()); } class targetHandler implements InvocationHandler{ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开启事务..."); Object returnValue = method.invoke(targetObject, args);//回调被代理目标的方法userDaoImpl.add(); System.out.println("提交事务"); return returnValue; } } public static void main(String[] args) { JDKProxy jdkProxy = new JDKProxy(); Customer userDao = (Customer)jdkProxy.CustomerProxy(new CustomerImpl()); userDao.shopping(); } //写法2 @Test public void test1(){ Customer customer = new CustomerImpl(); Customer cus = (Customer) Proxy.newProxyInstance(customer.getClass().getClassLoader(), customer.getClass().getInterfaces(),new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub return method.invoke(proxy, args); } }); cus.shopping(); } }
3)不足点:jdk动态代理,必须是面向接口,目标业务类必须实现接口
2.CGLIB代理
1.原理:利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
2.实现方法:
package proxy.cglib; import java.lang.reflect.Method; import org.junit.Test; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import proxy.model.Customer; public class CGLIBProxy { //写法1 private Object targetObject; private Object createProxy(Object obj){ targetObject = obj; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(targetObject.getClass());//设置代理对象,父类,说明是继承,所有代理对象不能为final enhancer.setCallback(new MyHandler()); return enhancer.create();//创建代理 } class MyHandler implements MethodInterceptor{ @Override public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable { System.out.println("开启事务.."); Object returnValue = method.invoke(targetObject, args); System.out.println("提交事务...."); return returnValue; } } @Test public void test1() { CGLIBProxy cglibProxy = new CGLIBProxy(); Customer customer = (Customer)cglibProxy.createProxy(new Customer()); customer.eat(); } //写法2 @Test public void test2(){ Customer customer = new Customer(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(customer.getClass()); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy arg3) throws Throwable { if(method.getName().equals("eat")){ System.out.println("customer的eat方法被拦截了。。。。"); Object invoke = method.invoke(proxy, args); System.out.println("真实方法拦截之后。。。。"); return invoke; } // 不拦截 return method.invoke(proxy, args); } }); Customer cus = (Customer) enhancer.create(); cus.eat(); } }
3.注意点:被代理目标不是是final修饰的类(final修饰类不能被继承)
spring aop代理原理
1.注意点:
- 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
- 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
- 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
2.强制把jdk代理转换成cglib代理
- 添加CGLIB库,SPRING_HOME/cglib/*.jar
- 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class = "true" />
传统AOP有默认的实现代理机制,可不需要专门指定代理,如自定义代理对象,可在类生成的时候自动代理,自动代理的方式主要有2种,一种是基于Bean名称的自动代理BeanNameAutoProxyCreator,另外一种是基于切面信息的自动代理DefaultAdvisorAutoProxyCreator
spring mvc 使用DefaultAdvisorAutoProxyCreator实现自动代理 配置
<!--定义一个表示声明使用自动代理的类 --> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> <!-- 定义代理类(本示例为异常类) --> <bean id="exceptionHandler" class="com.kaizhi.platform.util.ExceptionHandler"/> <!-- 定义支持正则表达式的通知 --> <bean id="exceptionHandlerAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref bean="exceptionHandler"/> </property> <property name="patterns"> <value>.save*.*</value>//正则匹配需要拦截的方法 </property> </bean>
spring mvc 使用BeanNameAutoProxyCreator自动代理配
<!-- 基于BeanNameAutoProxyCreator,Bean名称的自动代理 --> <!-- 定义代理类 --> <bean id="exceptionHandler" class="com.kaizhi.platform.util.ExceptionHandler"/> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <!-- 拦截的业务bean --> <property name="beanNames" value="*adminFinanceService"/> <!-- 拦截的通知 --> <property name="interceptorNames" value="exceptionHandler"/> </bean>