0
点赞
收藏
分享

微信扫一扫

SpringAOP联盟(3)—代理工厂

Mhhao 2021-09-24 阅读 16

序:代理对象的创建

无论是AspecJProxyFactoryProxyFactoryBeanProxyFactory大体逻辑都是:

  1. 填充ProxyCreatorSupport,实际上它是Advised子类,即填充代理配置类;
  2. 得到JDK或者CGLIB的AopProxy;
  3. Proxy Bean被调用时,被invoke或intercept方法拦截,并且会调用ProxyCreatorSupport(AdvisedSupport)getInterceptorsAndDynamicInterceptionAdvice方法去初始化advice和各个方法上的拦截器链并缓存

上述三个类本身并没有什么关系,但是都继承自ProxyCreatorSupport,创建代理对象的核心就是在ProxyCreatorSupport中实现的。

一、通过ProxyFactoryBean配置

配置类:

@Configuration
public class MyConfig {
@Bean
public LogMethodBeforeAdvice logMethodBeforeAdvice() {
return new LogMethodBeforeAdvice();
}

@Bean("tService")
public TService tService() {
return new TService();
}

@Bean("proxyFactoryBean")
public ProxyFactoryBean proxyFactoryBean(TService tService) {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
//代理的目标对象,效果等效于setTargetSource()
proxyFactoryBean.setTarget(tService);
//设置`String[] interceptorNames`,以便后续初始化"拦截器链"。
proxyFactoryBean.setInterceptorNames("logMethodBeforeAdvice");
return proxyFactoryBean;
}
}

拦截器类:

public class LogMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("this is logMethodBeforeAdvice!");
}
}

目标类:

public class TService {
public void run1(){
System.out.println("This is a run1() Method!");
}
}

测试类:

public class TestProxy {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
//可以使用@Primary指定元素,或直接使用name名获取。
//Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException:
// No qualifying bean of type 'com.tellme.Impl.proxy.TService' available:
// expected single matching bean but found 2: tService,proxyFactoryBean。(或生成两个Bean名字)
//TService bean = applicationContext.getBean(TService.class);
//若使用Class获取Bean,会获取到两个Bean对象。
TService bean = (TService)applicationContext.getBean("proxyFactoryBean");
bean.run1();
System.out.println(bean.getClass());
}
}

结果:

this is logMethodBeforeAdvice!
This is a run1() Method!
class com.tellme.Impl.proxy.TService$EnhancerBySpringCGLIB$6ac1bfc1

如测试案例所示,构建ProxyFactoryBean的过程实际上是完成的是代理配置。即填充Advised对象。而Advised对象实际上是由多个Advisor组成。

ProxyFactoryBean便是借助于控制反转,只是传入Interceptors类名便完成拦截对象的填充。

1.1 初始化AdvisorChain

代理对象的创建,首先要创建配置对象,即实现Advised接口,Spring实现了该接口。我们最终通过ProxyCreatorSupport提供的API便可以完成配置。

配置Advised,实际上执行的是initializeAdvisorChain()

  1. 在IOC容器中通过BeanName获取到Advice对象,(当然这种情况属于单例,而Spring作为一个框架,实际上会考虑原型模式以及通配符的情况)。
  2. 借助AdvisorAdapterRegistryAdvice转换为Advisor(当然pointcut是Pointcut.TRUE,拦截所有的方法)。
  3. Advisor加入到AdvicedSupport维护的列表中。该代理对象会持有所有的Advisor
public class ProxyFactoryBean extends ProxyCreatorSupport
implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {

/** Whether the advisor chain has already been initialized. */
private boolean advisorChainInitialized = false;

//(步骤1:获取代理对象)
@Override
@Nullable
public Object getObject() throws BeansException {
//初始化AdvisorChain。
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
//(步骤2:初始化过滤器链)
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
//若拦截器链已经初始化,直接跳出。
if (this.advisorChainInitialized) {
return;
}
//该变量实际上是由proxyFactoryBean.setInterceptorNames("logMethodBeforeAdvice");设置的
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
}

// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}

// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
//若是拦截器名字以*结尾,要全局搜索出来(相当于一个批量处理)
//最终依旧会调用addAdvisorOnChainCreation加入到单例池中。
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}

else {
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice;
if (this.singleton || this.beanFactory.isSingleton(name)) {
// Add the real Advisor/Advice to the chain.
//若是拦截器为单例,那么在单例池中获取单例对象
advice = this.beanFactory.getBean(name);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
//若是多例,每次均产生一个拦截器对象
advice = new PrototypePlaceholderAdvisor(name);
}
//将获取到的拦截器对象加入到拦截器链中。
addAdvisorOnChainCreation(advice, name);
}
}
}
//设置标识为true。
this.advisorChainInitialized = true;
}
//(步骤3:将advice转转化为Advisor)
private void addAdvisorOnChainCreation(Object next, String name) {
// We need to convert to an Advisor if necessary so that our source reference
// matches what we find from superclass interceptors.
Advisor advisor = namedBeanToAdvisor(next);
if (logger.isTraceEnabled()) {
logger.trace("Adding advisor with name '" + name + "'");
}
//将Advisor加入到Advised的配置列表中
addAdvisor(advisor);
}
//(步骤4:转换为Advisor)
private Advisor namedBeanToAdvisor(Object next) {
try {
return this.advisorAdapterRegistry.wrap(next);
}
catch (UnknownAdviceTypeException ex) {
throw new AopConfigException("Unknown advisor type " + next.getClass() +
"; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," +
"which may also be target or TargetSource", ex);
}
}

}

上述是实际上是通过DefaultPointcutAdvisor(advice)将advice转换为了增强器Advisor。Pointcut使用的是Pointcut.TRUE,即拦截target中所有的Method

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
@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);
}
}

调用addAdvisor(advisor);是将Advisor加入到AdvisedSupport维护的List<Advisor>中。创建出的代理对象会包含Advised的配置。

2 获取代理对象

源码:org.springframework.aop.framework.ProxyFactoryBean#getObject

public Object getObject() throws BeansException {  
//初始化AdvisorChain(此时我们在这...)
initializeAdvisorChain();
if (isSingleton()) {
//返回单例对象。
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
private synchronized Object getSingletonInstance() {  
if (this.singletonInstance == null) {
//根据设置的targetName,去单例池中获取bean对象
this.targetSource = freshTargetSource();
//这一步是如果你手动没有去设置需要被代理的接口,Spring还是会去帮你找看你有没有实现啥接口,然后全部给你代理上。可见Spring的容错性是很强的
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
//Spring自动寻找接口,并且设置接口
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
//创建代理对象。
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
//返回代理对象
protected Object getProxy(AopProxy aopProxy) {
//实际上是调用的AopProxy对象创建的代理对象。
return aopProxy.getProxy(this.proxyClassLoader);
}

代理的创建可以参考——SpringAOP联盟(2)— Cglib代理流程分析

1. 2. 脱离IOC容器使用

public class ProxyFactoryBeanDemo {
public static void main(String[] args) {
String pointcutExpression = "execution (void com.tellme.Impl.proxy.TService.run1())";
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(new TService());
//设置切点
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(pointcutExpression);
Advice advice=(MethodInterceptor) invocation -> {
System.out.println("请求before...");
Object obj = invocation.proceed();
System.out.println("请求after...");
return obj;
};
//创建Advisor
Advisor advisor=new DefaultPointcutAdvisor(pointcut,advice);
//加入到Advised过滤器链中
proxyFactoryBean.addAdvisor(advisor);
//获取代理对象
TService service = (TService)proxyFactoryBean.getObject();
service.run1();
System.out.println(service.toString());
}
}

借助IOC容器,实际上做两件事情:

  • 初始化AdvisorChain,根据传入的proxyFactoryBean.setInterceptorNames("");去IOC容器中获取Advice对象。
  • 根据Advised配置,创建Proxy对象。

最后都借助于getProxy(createAopProxy())产生代理对象。所以PoxyFactoryBean可以不借助于IOC执行。

二、 通过AspectJProxyFactory配置

@Aspect
public class MyAspect {
@Pointcut("execution (void com.tellme.Impl.proxy.TService.run1())")
private void beforeAdd(){
}
@Before("beforeAdd()")
public void before1(){
System.out.println("---------before----------");
}
}
public class Demo {
public static void main(String[] args) {
AspectJProxyFactory proxyFactory=new AspectJProxyFactory(new TService());
proxyFactory.addAspect(MyAspect.class);
TService bean =proxyFactory.getProxy();
bean.run1();
}
}

我们传入MyAspect类,便自动完成了代理。

  • 需要注意的是:使用AspectjProxyFactory基于切面类创建代理对象时,我们指定的切面类必须包含@Aspect注解。

  • 虽然我们自己可以通过编程的方式可以通过AspectjProxyFactory创建基于@Aspect切面类的代理类,但是通过<aop:aspectj-autoproxy/>(@EnableAspectJAutoProxy)使用基于注解的AspectJ风格的AOP时,Spring内部不是通过AspectjProxyFactory创建的代理对象,而是通过ProxyFactory。

三、通过ProxyFactory配置

分析如该文章所示——SpringAOP联盟(2)— Cglib代理流程分析

文章参考

https://blog.csdn.net/f641385712/article/details/88926243

举报

相关推荐

0 条评论