/** * Apply a lock (preferably a read lock allowing multiple concurrent access) to the bean. Callers should replace the * bean input with the output. * * @param bean the bean to lock * @param lock the lock to apply * @return a proxy that locks while its methods are executed */ private Object getDisposalLockProxy(Object bean, final Lock lock) { ProxyFactory factory = new ProxyFactory(bean); factory.setProxyTargetClass(proxyTargetClass); factory.addAdvice(new MethodInterceptor() { public Object invoke(MethodInvocation invocation) throws Throwable { lock.lock(); try { return invocation.proceed(); } finally { lock.unlock(); } } }); return factory.getProxy(); }
/** * Instantiates a new managed subsystem proxy factory. */ public SubsystemProxyFactory() { addAdvisor(new DefaultPointcutAdvisor(new MethodInterceptor() { public Object invoke(MethodInvocation mi) throws Throwable { Method method = mi.getMethod(); try { return method.invoke(locateBean(mi), mi.getArguments()); } catch (InvocationTargetException e) { // Unwrap invocation target exceptions throw e.getTargetException(); } } })); }
/** * InvocationHandler 接口中的 invoke 方法具体实现,封装了具体的代理逻辑 * * @param proxy * @param method * @param args * @return 代理方法或原方法的返回值 * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodMatcher methodMatcher = advised.getMethodMatcher(); // 使用方法匹配器 methodMatcher 测试 bean 中原始方法 method 是否符合匹配规则 if (methodMatcher != null && methodMatcher.matchers(method, advised.getTargetSource().getTargetClass())) { // 获取 Advice。MethodInterceptor 的父接口继承了 Advice MethodInterceptor methodInterceptor = advised.getMethodInterceptor(); // 将 bean 的原始 method 封装成 MethodInvocation 实现类对象, // 将生成的对象传给 Adivce 实现类对象,执行通知逻辑 return methodInterceptor.invoke( new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args)); } else { // 当前 method 不符合匹配规则,直接调用 bean 中的原始 method return method.invoke(advised.getTargetSource().getTarget(), args); } }
@Override public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { // So well-known it doesn't even need an adapter. return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { // Check that it is supported. if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); }
@Override public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3); Advice advice = advisor.getAdvice(); if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[interceptors.size()]); }
public ConstructionProxy<T> create() throws ErrorsException { if (interceptors.isEmpty()) { return new DefaultConstructionProxyFactory<T>(injectionPoint).create(); } @SuppressWarnings("unchecked") Class<? extends Callback>[] callbackTypes = new Class[callbacks.length]; for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] == net.sf.cglib.proxy.NoOp.INSTANCE) { callbackTypes[i] = net.sf.cglib.proxy.NoOp.class; } else { callbackTypes[i] = net.sf.cglib.proxy.MethodInterceptor.class; } } // Create the proxied class. We're careful to ensure that all enhancer state is not-specific // to this injector. Otherwise, the proxies for each injector will waste PermGen memory try { Enhancer enhancer = BytecodeGen.newEnhancer(declaringClass, visibility); enhancer.setCallbackFilter(new IndicesCallbackFilter(methods)); enhancer.setCallbackTypes(callbackTypes); return new ProxyConstructor<T>(enhancer, injectionPoint, callbacks, interceptors); } catch (Throwable e) { throw new Errors().errorEnhancingClass(declaringClass, e).toException(); } }
/** * Variant of {@link #bindInterceptor(Class, Class...) bindInterceptor} that * allows constructor-injection of interceptors described by class, each * wrapped by a method interceptor wrapper. * @param classMatcher matches classes the interception should apply to. * For example: {@code only(Runnable.class)}. * @param methodMatcher matches methods the interception should apply to. * For example: {@code annotatedWith(Transactional.class)}. * @param methodInterceptorWrapper a wrapper applied to each of the specified interceptors. * @param methodInterceptorClasses chain of * {@link org.aopalliance.intercept.MethodInterceptor MethodInterceptor}s * used to intercept calls, specified by class. */ public void bindInterceptor(Matcher<? super Class<?>> classMatcher, Matcher<? super Method> methodMatcher, MethodInterceptorWrapper methodInterceptorWrapper, Class<?>... methodInterceptorClasses) { if (methodInterceptorClasses != null) { MethodInterceptor[] interceptors = new MethodInterceptor[methodInterceptorClasses.length]; int i = 0; for (Class<?> cls : methodInterceptorClasses) { if (!MethodInterceptor.class.isAssignableFrom(cls)) { addError("bindInterceptor: %s does not implement MethodInterceptor", cls.getName()); } else { @SuppressWarnings("unchecked") Class<? extends MethodInterceptor> c = (Class<? extends MethodInterceptor>) cls; interceptors[i++] = wrap(methodInterceptorWrapper, c); } } bindInterceptor(classMatcher, methodMatcher, interceptors); } }
private void bindMethodInterceptorForStringTemplateClassLoaderWorkaround() { bindInterceptor(Matchers.subclassesOf(JDBIHistoryManager.class), Matchers.any(), new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl == null) { Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader()); } try { return invocation.proceed(); } finally { Thread.currentThread().setContextClassLoader(cl); } } }); }
/** * Binds an interceptor that ensures the main ClassLoader is bound as the thread context * {@link ClassLoader} during JNI callbacks from mesos. Some libraries require a thread * context ClassLoader be set and this ensures those libraries work properly. * * @param binder The binder to use to register an interceptor with. * @param wrapInterface Interface whose methods should wrapped. */ public static void bindJNIContextClassLoader(Binder binder, Class<?> wrapInterface) { final ClassLoader mainClassLoader = GuiceUtils.class.getClassLoader(); binder.bindInterceptor( Matchers.subclassesOf(wrapInterface), interfaceMatcher(wrapInterface, false), new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { Thread currentThread = Thread.currentThread(); ClassLoader prior = currentThread.getContextClassLoader(); try { currentThread.setContextClassLoader(mainClassLoader); return invocation.proceed(); } finally { currentThread.setContextClassLoader(prior); } } }); }
/** * Binds an exception trap on all interface methods of all classes bound against an interface. * Individual methods may opt out of trapping by annotating with {@link AllowUnchecked}. * Only void methods are allowed, any non-void interface methods must explicitly opt out. * * @param binder The binder to register an interceptor with. * @param wrapInterface Interface whose methods should be wrapped. * @throws IllegalArgumentException If any of the non-whitelisted interface methods are non-void. */ public static void bindExceptionTrap(Binder binder, Class<?> wrapInterface) throws IllegalArgumentException { Set<Method> disallowed = ImmutableSet.copyOf(Iterables.filter( ImmutableList.copyOf(wrapInterface.getMethods()), Predicates.and(Predicates.not(IS_WHITELISTED), Predicates.not(VOID_METHOD)))); Preconditions.checkArgument(disallowed.isEmpty(), "Non-void methods must be explicitly whitelisted with @AllowUnchecked: " + disallowed); Matcher<Method> matcher = Matchers.not(WHITELIST_MATCHER).and(interfaceMatcher(wrapInterface, false)); binder.bindInterceptor(Matchers.subclassesOf(wrapInterface), matcher, new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { try { return invocation.proceed(); } catch (RuntimeException e) { LOG.warn("Trapped uncaught exception: " + e, e); return null; } } }); }
public AopAccessLoggerSupport() { setAdvice((MethodInterceptor) methodInvocation -> { MethodInterceptorHolder methodInterceptorHolder = MethodInterceptorHolder.create(methodInvocation); AccessLoggerInfo info = createLogger(methodInterceptorHolder); Object response; try { listeners.forEach(listener -> listener.onLogBefore(info)); response = methodInvocation.proceed(); info.setResponse(response); info.setResponseTime(System.currentTimeMillis()); } catch (Throwable e) { info.setException(e); throw e; } finally { //触发监听 listeners.forEach(listener -> listener.onLogger(info)); } return response; }); }
@Test public void testNullPrimitiveWithJdkProxy() { class SimpleFoo implements Foo { @Override public int getValue() { return 100; } } SimpleFoo target = new SimpleFoo(); ProxyFactory factory = new ProxyFactory(target); factory.addAdvice(new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { return null; } }); Foo foo = (Foo) factory.getProxy(); thrown.expect(AopInvocationException.class); thrown.expectMessage("Foo.getValue()"); assertEquals(0, foo.getValue()); }
@Test public void testNullPrimitiveWithCglibProxy() { Bar target = new Bar(); ProxyFactory factory = new ProxyFactory(target); factory.addAdvice(new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { return null; } }); Bar bar = (Bar) factory.getProxy(); thrown.expect(AopInvocationException.class); thrown.expectMessage("Bar.getValue()"); assertEquals(0, bar.getValue()); }
@Test public void testInterceptorInclusionMethods() { class MyInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { throw new UnsupportedOperationException(); } } NopInterceptor di = new NopInterceptor(); NopInterceptor diUnused = new NopInterceptor(); ProxyFactory factory = new ProxyFactory(new TestBean()); factory.addAdvice(0, di); assertThat(factory.getProxy(), instanceOf(ITestBean.class)); assertTrue(factory.adviceIncluded(di)); assertTrue(!factory.adviceIncluded(diUnused)); assertTrue(factory.countAdvicesOfType(NopInterceptor.class) == 1); assertTrue(factory.countAdvicesOfType(MyInterceptor.class) == 0); factory.addAdvice(0, diUnused); assertTrue(factory.adviceIncluded(diUnused)); assertTrue(factory.countAdvicesOfType(NopInterceptor.class) == 2); }
public DynamicAsyncInterfaceBean() { ProxyFactory pf = new ProxyFactory(new HashMap<>()); DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); if (Future.class.equals(invocation.getMethod().getReturnType())) { return new AsyncResult<String>(invocation.getArguments()[0].toString()); } return null; } }); advisor.addInterface(AsyncInterface.class); pf.addAdvisor(advisor); this.proxy = (AsyncInterface) pf.getProxy(); }
public DynamicAsyncMethodsInterfaceBean() { ProxyFactory pf = new ProxyFactory(new HashMap<>()); DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); if (Future.class.equals(invocation.getMethod().getReturnType())) { return new AsyncResult<String>(invocation.getArguments()[0].toString()); } return null; } }); advisor.addInterface(AsyncMethodsInterface.class); pf.addAdvisor(advisor); this.proxy = (AsyncMethodsInterface) pf.getProxy(); }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception { if (bean instanceof AspectJExpressionPointcutAdvisor) { return bean; } if (bean instanceof MethodInterceptor) { return bean; } List<AspectJExpressionPointcutAdvisor> advisors = beanFactory .getBeansForType(AspectJExpressionPointcutAdvisor.class); for (AspectJExpressionPointcutAdvisor advisor : advisors) { if (advisor.getPointcut().getClassFilter().matches(bean.getClass())) { ProxyFactory advisedSupport = new ProxyFactory(); advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice()); advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher()); TargetSource targetSource = new TargetSource(bean, bean.getClass(), bean.getClass().getInterfaces()); advisedSupport.setTargetSource(targetSource); return advisedSupport.getProxy(); } } return bean; }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception { if (Advice.class.isAssignableFrom(bean.getClass()) || Pointcut.class.isAssignableFrom(bean.getClass()) || Advisor.class.isAssignableFrom(bean.getClass()) || MethodInterceptor.class.isAssignableFrom(bean.getClass())) { return bean; } List<DefaultPointcutAdvisor> defaultPointcutAdvisors = beanFactory .getBeansForType(DefaultPointcutAdvisor.class); for (DefaultPointcutAdvisor advisor : defaultPointcutAdvisors) { if (advisor.getPointcut().getClassFilter().matches(bean.getClass())) { ProxyFactory advisedSupport = new ProxyFactory(); advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice()); advisedSupport.setMethodMatcher(advisor.getPointcut().getmethodMatcher()); advisedSupport .setTargetSource(new TargetSource(bean.getClass(), bean.getClass().getInterfaces(), bean)); return advisedSupport.getProxy(); } } return null; }
@Override protected void configure() { bindInterceptor(Matchers.any(), new AbstractMatcher<Method>() { @Override public boolean matches(Method method) { return getAuthAnnotations(method.getAnnotations()).isPresent(); } }, new MethodInterceptor() { @Override public Object invoke(MethodInvocation ctx) throws Throwable { Optional<Auth> methodAnnotation = getAuthAnnotations(ctx.getMethod().getAnnotations()); boolean allowAnon = methodAnnotation.map(Auth::pass).orElse(true); if (!allowAnon) { throw new Exception("Access denied"); } return ctx.proceed(); } }); }
/** * Binds the {@link ServiceProxiesAggregator} that MUST contain fields of types implementing {@link ServiceInterface} which are * the concrete proxy implementation to the services * * The {@link ServiceInterface} fields of {@link ServiceProxiesAggregator} implementing type are LAZY loaded by * {@link ServicesClientProxyLazyLoaderGuiceMethodInterceptor} which guesses what proxy implementation assign to the field: * <ul> * <li>If the {@link ServiceProxiesAggregator} extends {@link ServiceProxiesAggregatorForDefaultImpls}, the concrete {@link ServiceInterface}-implementing * proxy instance is taken from the client properties XML file, so some service impls might be accessed using a BEAN proxy while others might be accessed * using a REST proxy -depending on the properties file-</li> * <li>If the {@link ServiceInterface} field's BEAN implementation is available this one will be assigned to the field no matter what type the aggregator is</li> * </ul> * @param binder */ private void _bindServiceProxiesAggregators(final Binder binder) { // Inject all Map fields that matches the service interface types with the bean impl or proxy to be used // (this Map fields are injected by MapBinders created at ServicesForAppModulePrivateGuiceModule) binder.requestInjection(_serviceInterfaceTypesToImplOrProxyMappings); // Create a private binder to be used to inject the MethodInterceptor that will intercept all fine-grained // proxy accessor method calls at ServicesAggregatorClientProxy // The interceptor lazily loads the fine-grained proxy instances and makes the aggregator creation simpler PrivateBinder privateBinder = binder.newPrivateBinder(); privateBinder.bind(ServiceInterfaceTypesToImplOrProxyMappings.class) .toInstance(_serviceInterfaceTypesToImplOrProxyMappings); MethodInterceptor serviceProxyGetterInterceptor = new ServicesClientProxyLazyLoaderGuiceMethodInterceptor(_apiAppAndModule, _coreAppAndModules); privateBinder.requestInjection(serviceProxyGetterInterceptor); // the method interceptor is feeded with a map of service interfaces to bean impl or proxy created below // Bind the interceptor to ServiceProxiesAggregator type's fine-grained method calls binder.bindInterceptor(Matchers.subclassesOf(ServiceProxiesAggregator.class), Matchers.any(), serviceProxyGetterInterceptor); // Bind every services proxy aggregator implementation log.info("[ServiceProxyAggregator] > {}",_servicesProxiesAggregatorType); binder.bind(_servicesProxiesAggregatorType) .in(Singleton.class); }
/** * creates a proxy that dispatches invocations to the currently bound {@link ProcessInstance} * * @return shareable {@link ProcessInstance} */ private Object createSharedProcessInstance() { ProxyFactory proxyFactoryBean = new ProxyFactory(ProcessInstance.class, new MethodInterceptor() { public Object invoke(MethodInvocation methodInvocation) throws Throwable { String methodName = methodInvocation.getMethod().getName() ; logger.info("method invocation for " + methodName+ "."); if(methodName.equals("toString")) return "SharedProcessInstance"; ProcessInstance processInstance = Context.getExecutionContext().getProcessInstance(); Method method = methodInvocation.getMethod(); Object[] args = methodInvocation.getArguments(); Object result = method.invoke(processInstance, args); return result; } }); return proxyFactoryBean.getProxy(this.classLoader); }
private Environment environmentForImage(int maxWidth, boolean invert) { Map<String, Object> specification = new HashMap<>(); specification.put("banner.image.width", maxWidth); specification.put("banner.image.invert", invert); ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setInterfaces(Environment.class); proxyFactoryBean.addAdvice((MethodInterceptor) invocation -> { String containsProperty = "containsProperty"; String getProperty = "getProperty"; List<String> toHandle = Arrays.asList(containsProperty, getProperty); String methodName = invocation.getMethod().getName(); if (toHandle.contains(methodName)) { String key = String.class.cast(invocation.getArguments()[0]); if (methodName.equals(containsProperty)) { return (specification.containsKey(key) || this.environment.containsProperty(key)); } if (methodName.equals(getProperty)) { return specification.getOrDefault(key, this.environment.getProperty(key)); } } return invocation.getMethod().invoke(this.environment, invocation.getArguments()); }); return Environment.class.cast(proxyFactoryBean.getObject()); }
/** * Creates an interceptor that chains other interceptors. * * @param interceptors * instances of {@link MethodInterceptor}. * @return interceptor that enclose other interceptors or Interceptors.EMPTY instance if interceptors argument is * null or empty */ public static MethodInterceptor create(final MethodInterceptor... interceptors) { if (ArrayUtils.isEmpty(interceptors)) { return Interceptors.EMPTY; } final List<MethodInterceptor> flatlist = new ArrayList<>(); for (final MethodInterceptor interceptor : interceptors) { assert (interceptor != null); if (interceptor instanceof Interceptors) { flatlist.addAll(Arrays.asList(((Interceptors) interceptor).interceptors)); } else if (EMPTY != interceptor) { flatlist.add(interceptor); } } if (flatlist.isEmpty()) { return EMPTY; } else if (flatlist.size() == 1) { return flatlist.get(0); } return new Interceptors(flatlist.toArray(new MethodInterceptor[flatlist.size()])); }
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException { if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException(adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { // So well-known it doesn't even need an adapter. return new DefaultPointcutAdvisor(advice); } for (AdvisorAdapter adapter : this.adapters) { // Check that it is supported. if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor(advice); } } throw new UnknownAdviceTypeException(advice); }
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3); Advice advice = advisor.getAdvice(); if (advice instanceof MethodInterceptor) { interceptors.add((MethodInterceptor) advice); } for (AdvisorAdapter adapter : this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[interceptors.size()]); }
@Bean(name = CURRENT_USER_BEAN) Authentication currentUser() { return ProxyFactory.getProxy(Authentication.class, new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { SecurityContext securityContext = SecurityContextHolder.getContext(); Authentication authentication = securityContext.getAuthentication(); if (authentication == null) { throw new AuthenticationCredentialsNotFoundException("No authentication found in current security context"); } return invocation.getMethod().invoke(authentication, invocation.getArguments()); } }); }
public void testGetThis() { final AtomicReference<Object> lastTarget = new AtomicReference<>(); Injector injector = Guice.createInjector( new AbstractModule() { @Override protected void configure() { bindInterceptor( Matchers.any(), Matchers.any(), new MethodInterceptor() { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { lastTarget.set(methodInvocation.getThis()); return methodInvocation.proceed(); } }); } }); Interceptable interceptable = injector.getInstance(Interceptable.class); interceptable.foo(); assertSame(interceptable, lastTarget.get()); }
@SuppressWarnings("unchecked") @Test public void verifyAddingRedirectAdviceToExistingProxy() { AmazonS3 amazonS3 = mock(AmazonS3.class); ProxyFactory factory = new ProxyFactory(amazonS3); factory.addAdvice(new TestAdvice()); AmazonS3 proxy1 = (AmazonS3) factory.getProxy(); assertThat(((Advised) proxy1).getAdvisors().length, is(1)); AmazonS3 proxy2 = AmazonS3ProxyFactory.createProxy(proxy1); Advised advised = (Advised) proxy2; assertThat(advised.getAdvisors().length, is(2)); List<Class<? extends MethodInterceptor>> advisorClasses = new ArrayList<>(); for (Advisor advisor : advised.getAdvisors()) { advisorClasses.add(((MethodInterceptor) advisor.getAdvice()).getClass()); } assertThat(advisorClasses, hasItems(TestAdvice.class, AmazonS3ProxyFactory.SimpleStorageRedirectInterceptor.class)); }