序:代理对象的创建
无论是AspecJProxyFactory
、ProxyFactoryBean
、ProxyFactory
大体逻辑都是:
- 填充
ProxyCreatorSupport
,实际上它是Advised
子类,即填充代理配置类; - 得到JDK或者CGLIB的AopProxy;
- 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()
。
- 在IOC容器中通过BeanName获取到
Advice
对象,(当然这种情况属于单例
,而Spring作为一个框架,实际上会考虑原型
模式以及通配符
的情况)。 - 借助
AdvisorAdapterRegistry
将Advice
转换为Advisor
(当然pointcut是Pointcut.TRUE
,拦截所有的方法)。 - 将
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代理流程分析