- 为什么要使用代理模式呢?
打个比方,我虽然不会打篮球,但我很喜欢A锥,可是国内我又买不起,
发现海淘的A锥,既经济又实惠(咱也不知道是不是真货,咱也不敢问),
不过我发现我去访问海外电商极度费劲,此时我该怎么办?
我突然想到了代购老黄,我们可以通过老黄啊,来帮我们获取到我们心仪的A锥。
从静态代理的角度我们分析一下老黄代理如何运作:
所以对于老黄,也就代理来说,其实就是一个搬运工。
也比如我们的博客系统,我们查看一个文章,如果文章中有个特别大的图片需要加载,
此时如果等在加载完图片再进行展示图片以后的文章内容,是非常耗时的操作,
那么此时我们就可以使用Proxy来先代替那个图片。
- 我们先看看静态代理是如何实现上述鞋工厂的:
1》先创建一个鞋工厂接口:
public interface ShoeFactory { void saleShoe(int size); }
2》创建一个AJ鞋厂来实现这个接口:
public class AJFactory implements ShoeFactory { @Override public void saleShoe(int size) { System.out.println("根据您的需求,为您定制了一个size为:" + size + "的AJ"); } }
3》看看老黄是如何代理的:
/** * 代理类 */ public class LaohuangProxy implements ShoeFactory { private ShoeFactory factory; public LaohuangProxy(ShoeFactory factory) { super(); this.factory = factory; } @Override public void saleShoe(int size) { doSomethingBefore();//前置增强 factory.saleShoe(size); doSomethingAfter();//后置增强 } private void doSomethingAfter() { System.out.println("提供快递服务一条龙"); } private void doSomethingBefore() { System.out.println("根据您的需求进行市场调研"); } public static void main(String[] args) { AJFactory factory = new AJFactory();//1.有一个AJ鞋工厂 LaohuangProxy laohuangProxy = new LaohuangProxy(factory);//2.老黄代理 laohuangProxy.saleShoe(43);//3.帮我订购一双43码鞋 } }
但此时,快过情人节了,这空手确实不太行啊,我准备给我的女神小娜个迪奥999口红(就是这么大气),
但是专柜已经被抢空了,所以我又想到了无所不能的老黄,找他帮我代购一波:
如果继续使用静态代理,我们需要再创建一个口红制造厂接口和迪奥口红工厂类,话不多说,撸码就完了:
1》声明一个口红工厂接口
public interface LipstickFactory { void saleLipstick(String color); }
2》创建一个迪奥工厂类:
public class DiorFactory implements LipstickFactory { @Override public void saleLipstick(String color) { System.out.println("根据您的需求,为您包装了一个颜色为:" + color + "的迪奥口红"); } }
3》看看老黄代理的改动:
public class LaohuangProxy implements ShoeFactory, LipstickFactory { //改动1:需要多继承一个接口 private ShoeFactory factory; private LipstickFactory lipstickFactory;//改动2:由于代理类只是一个搬运工,所以需要多包含一个口红工厂 public LaohuangProxy(ShoeFactory factory) { super(); this.factory = factory; } //改动3:需要实现一个新的构造函数 public LaohuangProxy(LipstickFactory lipstickFactory) { super(); this.lipstickFactory = lipstickFactory; } @Override public void saleShoe(int size) { doSomethingBefore();//前置增强 factory.saleShoe(size); doSomethingAfter();//后置增强 } //改动4:需要新增一个口红售卖类 @Override public void saleLipstick(String color) { doSomethingBefore();//前置增强 lipstickFactory.saleLipstick(color); doSomethingAfter();//后置增强 } private void doSomethingAfter() { System.out.println("提供快递服务一条龙"); } private void doSomethingBefore() { System.out.println("根据您的需求进行市场调研"); } main{....} }
可以看出一共有四处改动,所以静态代理的弊端就是,我么如果每增加一个代理对象,代理类就需要在原有基础上有很大的改动。
- 所以此时我们必须要引入动态代理,那动态代理是如何实现的呢?
动态代理的话,老黄就不是一个人代购了,老黄开了一家代购公司,
话不多BB,撸代码:
(口红工厂和鞋工厂对象同上)
动态代理的总代理对象如下:
public class LaohuangCompanyProxy implements InvocationHandler { private Object factory; public Object getFactory() { return factory; } public void setFactory(Object factory) { this.factory = factory; } public Object getProxyInstance() { //传入this说明调度的所有员工必须遵循当前类的业务增强 return Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), this); } /** * 通过动态代理对象方法进行增强(动态代理对象调用方法时调用本方法) * * @param proxy * @param method 方法名 * @param args 方法参数 * @return */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doSomethingBefore(); Object res = method.invoke(factory, args); doSomethingAfter(); return res; } private void doSomethingAfter() { System.out.println("提供快递服务一条龙"); } private void doSomethingBefore() { System.out.println("根据您的需求进行市场调研"); } public static void main(String[] args) { ShoeFactory shoeFactory = new AJFactory(); LipstickFactory lipstickFactory = new DiorFactory(); LaohuangCompanyProxy laohuangCompanyProxy = new LaohuangCompanyProxy();//声明总代理对象 laohuangCompanyProxy.setFactory(shoeFactory); ShoeFactory shoeFactory1 = (ShoeFactory) laohuangCompanyProxy.getProxyInstance();//通过总代理对象分配出一个代理运行对象 shoeFactory1.saleShoe(43); laohuangCompanyProxy.setFactory(lipstickFactory); LipstickFactory lipstickFactory1 = (LipstickFactory) laohuangCompanyProxy.getProxyInstance(); lipstickFactory1.saleLipstick("斩男色"); } }
关键代码:
1》【Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), this);】
生成一个代理对象,通过总代理对象,创建一个动态代理对象:
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
ClassLoader loader: 定义了由哪个类加载器来对生成的代理对象进行加载
Class<?>[] interfaces: 表示给代理对象提供一组什么接口,相当于用代理对象去实现这些接口中的方法,这样就可以直接调用了
InvocationHandler h:表示我这个动态代理对象在调用方法时,会关联到哪一个InvocationHandler上
2》【Object invoke(Object proxy, Method method, Object[] args)】
Object invoke(Object proxy, Method method, Object[] args)
Object proxy: 所代理的真实对象
Method method:所要调用的某个方法
Object[] args: 调用方法中的参数
我们Debug看一下【shoeFactory1】的真正类型,是一个JDK帮我们生成的动态代理类型。
- 我们分析下AOP的是如何使用JDK动态代理的呢?
在Spring-Aop源文件中类【JdkDynamicAopProxy】实现了【InvocationHandler】:
所以同样也实现了invoke方法,那么【@Transactional】注解实现是如何的呢?
调用了【invoke】方法后,通过责任链的方式,交给对应的拦截器【TransactionInterceptor】去进行aop拦截
@Override @Nullable public Object invoke(MethodInvocation invocation) throws Throwable { // Work out the target class: may be {@code null}. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }
然后进入到【invokeWithinTransaction】,我们可以看下源码:
@Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource(); final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { //开启事务,关闭自动提交 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. retVal = invocation.proceedWithInvocation();//执行方法本身 } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex);//异常提交回滚 throw ex; } finally { cleanupTransactionInfo(txInfo); } commitTransactionAfterReturning(txInfo);//未出现异常则直接进行提交 return retVal; } else { final ThrowableHolder throwableHolder = new ThrowableHolder(); // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> { TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); try { return invocation.proceedWithInvocation(); } catch (Throwable ex) { if (txAttr.rollbackOn(ex)) { // A RuntimeException: will lead to a rollback. if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } else { throw new ThrowableHolderException(ex); } } else { // A normal return value: will lead to a commit. throwableHolder.throwable = ex; return null; } } finally { cleanupTransactionInfo(txInfo); } }); // Check result state: It might indicate a Throwable to rethrow. if (throwableHolder.throwable != null) { throw throwableHolder.throwable; } return result; } catch (ThrowableHolderException ex) { throw ex.getCause(); } catch (TransactionSystemException ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); ex2.initApplicationException(throwableHolder.throwable); } throw ex2; } catch (Throwable ex2) { if (throwableHolder.throwable != null) { logger.error("Application exception overridden by commit exception", throwableHolder.throwable); } throw ex2; } } }
总结,所有的AOP都是基于动态代理增强,并且如果面试官问@Transactional的实现原理是什么,不要只说动态代理,要别责任链、连接器以及实现流程大致说详细。