Spring 에이전트 생 성 및 에이전트 구현
61083 단어 #자바 소스 코드 분석Spring 소스 코드 분석원본 코드 읽 기
Spring AOP 와 Spring 업무 의 실현 은 모두 대 리 를 바탕 으로 하기 때문에 이 부분 을 추출 하여 참고 하 시기 바 랍 니 다.
1. 대리 공장 초기 화: ProxyFactory
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
//..................
//
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// targetClass
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
// ,
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// Advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
//
return proxyFactory.getProxy(getProxyClassLoader());
//...................
}
차단 기 는 Advisor 의 적합 한 처리 로 봉 인 됩 니 다. 이쪽 을 보십시오.
@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);
}
getProxy 방법 은 주로 두 가지 절 차 를 포함한다.
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
2. 대리 실현
2.1 에이전트 선택 (cglib, jdk)
프 록 시 를 만 드 는 방법 createProxy 는 설정 및 계승 여부 에 따라 각각 Jdk 또는 Cglib 프 록 시 를 생 성 합 니 다.
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
//.......................
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//
return proxyFactory.getProxy(getProxyClassLoader());
}
public Object getProxy(ClassLoader classLoader) {
/**
* @see JdkDynamicAopProxy#getProxy(ClassLoader)
* @see CglibAopProxy#getProxy
*/
return createAopProxy().getProxy(classLoader);
}
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
/**
* CGLIB 、 、
* CGLIB
* JDK
* AopProxy ,
*/
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.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
2.2 대리 실현 의 두 가지 방식
3.1 JdkDynamicAopProxy
JDK 대 리 는 주로 인터페이스 에이전트 에 인용 되 는데 그 는 Invocation Handler 인 터 페 이 스 를 계승 하여 getProxy, Invoke 방법 을 실현 해 야 한다.
4.1 getProxy
일반적인 쓰기: getProxy
/**
* JDK , InvocationHandler , invoke , proxy 。
* invoke
* @see #invoke(Object, Method, Object[])
*/
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
4.2 invoke
이쪽 의 invoke 방법 은 주로 이 몇 단계 로 나 뉜 다.
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//...........
try {
/**
* equals、hash、method
*/
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
//...................
}
// ,
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//.....................
/**
*
* Map> .
*/
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
/**
* , method.invoke
*/
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
/**
* invocation, invocation
* @see ReflectiveMethodInvocation#proceed()
*/
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
//
Class<?> returnType = method.getReturnType();
//.............
return retVal;
}
finally {
//....................
}
}
5.1 차단기 체인 가 져 오기
여기 서 볼 수 있 습 니 다. 차단기 체인 을 가 져 오 는 방법 은?
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
5.2 차단기 체인 처리
차단기 체인 이 비어 있 지 않 으 면 일치 하 는 모든 차단기 체인 (method 의 invoke 호출) 을 계속 실행 합 니 다.
@Override
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
/**
*
*/
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
/**
* ,
*/
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
/**
*
*/
return proceed();
}
}
else {
/**
* invoke
*/
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
3.2 CglibAopProxy
cglib 는 Enhancer 류 를 통 해 사용 해 야 하기 때문에 이쪽 의 조작 도 이런 종 류 를 구축 하여 구체 적 인 조작 을 실현 합 니 다.
4.1 Enhancer 를 만 들 고 속성 설정
@Override
public Object getProxy(ClassLoader classLoader) {
try {
//.................
// Enhancer , CGLB --
Enhancer enhancer = createEnhancer();
//....... ,
//
Callback[] callbacks = getCallbacks(rootClass);
//.......................
// Enhancer
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException ex) {
// ..................
}
}
4.2 차단기 체인 가 져 오기
이 인 터 페 이 스 는 Spring 이 지원 하 는 것 으로 그의 intercept 방법 을 실현 하면 대리 의 목적 을 실현 할 수 있 습 니 다.
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
//............
/**
* 66. ,DynamicAdvisedInterceptor Methodlnterceptor, intercept CGLB
* @see DynamicAdvisedInterceptor#intercept(Object, Method, Object[], MethodProxy)
*/
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
//............
// Callback
Callback[] mainCallbacks = new Callback[] {aopInterceptor, targetInterceptor, new SerializableNoOp(), targetDispatcher, this.advisedDispatcher, new EqualsInterceptor(this.advised),new HashCodeInterceptor(this.advised)};
//.......................
return callbacks;
}
즉, 여기 서 되 돌아 오 는 콜백 리 셋 배열 은 사실 Dynamic Advised Interceptor 의 실현 입 니 다. 콜백 배열 을 Enhancer 에 설정 하여 호출 을 돕 습 니 다. Dynamic Advised Interceptor 는 MethodInterceptor 인 터 페 이 스 를 실현 하고 intercept 방법 을 실현 하 였 습 니 다. 여기 있 는 itercept 의 실현 은 JDK 대리 와 같 습 니 다.
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Rails Turbolinks를 페이지 단위로 비활성화하는 방법원래 Turobolinks란? Turbolinks는 링크를 생성하는 요소인 a 요소의 클릭을 후크로 하고, 이동한 페이지를 Ajax에서 가져옵니다. 그 후, 취득 페이지의 데이터가 천이 전의 페이지와 동일한 것이 있...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.