1、Advice:增强描述接口,spring提供的增强(Advice)
Spring只提供方法级别的连接点增强,所以以下说的增强全部是方法级别的增强。
1.1、方法before增强MethodBeforeAdvice
顾名思义方法前置增强就是在方法执行之前织入增强的逻辑代码。
使用案例:
public class UserServiceRegistryBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("注册用户前记录一下记录日志。。。。。");
}
}
1.2、方法AfterReturning增强AfterReturningAdvice
在方法正常返回之后织入增强的逻辑代码。
使用案例:
public class UserviceRegistryAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("注册用户完毕后发送短信通知。。。");
}
}
1.3、方法Around增强MethodInterceptor
包围方法织入增强的逻辑代码。
使用案例:
public class UserServiceRegistryAroundAdvice implements MethodInterceptor(使用aop联盟定义的MethodInterceptor接口) {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("around advice before...");
methodInvocation.proceed();
System.out.println("around advice after...");
return null;
}
}
1.4、方法抛出异常后增强ThrowsAdvice
方法抛出异常后织入增强的逻辑代码。
使用案例:
public class UserServiceRegistryThrowsAdvice implements ThrowsAdvice {
/*
由于ThrowsAdvice接口没有定义热任何方法,如何使用呢,使用规则如下:
1:定义的方法名称必须叫afterThrowing。
2:参数的格式为[Method method, Object[] args, Object target], Throwable throwable。
[Method method, Object[] args, Object target] :表示可选参数,但是要么都提供,要么都不提供。
Throwable throwable : throwable参数必须需要, 可以定义多个ThrowsAdvice,来处理不同的类型异常,
比如ThrowsAdvice1处理SqlException.
比如ThrowsAdvice2处理自定义ServiceException, 使用很灵活。
*/
public void afterThrowing(Method method, Object[] args, Object target, Throwable throwable){
System.out.println("方法执行异常。。。。。。");
System.out.println(throwable.getMessage());
System.out.println("成功回滚事务。。。。。。");
}
}
1.5、方法finally增强
Finally增强其实是AfterReturningAdvice 和ThrowsAdvice 的结合体,用来做比如stream关闭等功能。
1.6、类级别引介增强DelegatingIntroductionInterceptor
引介是一个特殊的增强,能为类动态的添加属性和方法,这样可以给一个类动态去实现某接口,也可以为类动态的添加接口的实现逻辑,让业务类成为接口的实现类。
使用案例: 给目标类是是实现SenderMsgService 接口,实现的逻辑为如下。
public class SendeMsgIntroductionAdvice extends DelegatingIntroductionInterceptor implements SenderMsgService {
@Override
public void sendMsg(String phone) {
System.out.println("发送短信给手机号:" + phone);
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
return super.invoke(mi);
}
}
2、Pointcut:切点描述接口(SpringAop用于描述切点的接口)
切点的含义我们知道是描述那些连接点的,在SpringAOP中Pointcut接口描述的是方法级别的连接点,也就是说是描述的连接点是:那些类的那些方法,我们看其源码就能知道所以然。
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*/
描述那些类
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
描述那些方法
MethodMatcher getMethodMatcher();
/**
* Canonical Pointcut instance that always matches.
*/
提供一个默认全部类的全部方法为切点。
Pointcut TRUE = TruePointcut.INSTANCE;
}
Pointcut类图结构如下:
3、Advisor:切面描述接口(SpringAop 提供用于描述切面的接口)
我们知道切面Advisor = 切点(Pointcut) + 增强(Advice)。
Advisor接口源码:
public interface Advisor {
/**
* Return the advice part of this aspect. An advice may be an
* interceptor, a before advice, a throws advice, etc.
* @return the advice that should apply if the pointcut matches
* @see org.aopalliance.intercept.MethodInterceptor
* @see BeforeAdvice
* @see ThrowsAdvice
* @see AfterReturningAdvice
*/
切面需要提供增强实例
Advice getAdvice();
/**
* Return whether this advice is associated with a particular instance
* (for example, creating a mixin) or shared with all instances of
* the advised class obtained from the same Spring bean factory.
* <p><b>Note that this method is not currently used by the framework.</b>
* Typical Advisor implementations always return {@code true}.
* Use singleton/prototype bean definitions or appropriate programmatic
* proxy creation to ensure that Advisors have the correct lifecycle model.
* @return whether this advice is associated with a particular target instance
*/
boolean isPerInstance();
}
Advisor接口类图:
PointcutAdvisor接口:切点切面接口,引介切面我们不做过多描述。
PointcutAdvisor接口源码:
public interface PointcutAdvisor extends Advisor {
获取切点,加上父类的获取增强,刚好可以描述一个切点切面
Pointcut getPointcut();
}
PointcutAdvisor的接口类图:
4、ProxyConfig(Spring提供的SpringAop配置接口):主要配置代理方式:proxyTargetClass 、optimize 等
Advised(也是Spring配置SpringAop的接口)主要作用是切面的添加、删除等操作addAdvisor、removeAdvisor、 Advisor[] getAdvisors()等
我们知道Aop的核心就是生成代理类,那么怎么生成代理类呢?是使用ObjenesisCglibAopProxy还是JdkDynamicAopProxy,是否需要暴露生成好的代理对象呢?需要织入的增强是什么?切点是什么?这些都是需要开发者自己配置的,因此为了实现灵活配置SpringAop提供了ProxyConfig、Advised两个接口以及内置一下实现来完成AOP的配置。其类图如下:
5、AopProxy(Spring提供的Aop代理接口用于生成代理对象的)
Aop的核心就是根据AOP的配置生成代理类,AopProxy就是干这个事情的,我们先来看看AopProxy的类图:
根据类图我们可以看出SpringAOP提供了两种生成代理类以及代理对象的方式,JDK动态代理、CGLIB动态代理。
ObjenesisCglibAopProxy继承于CglibAopProxy 在 CglibAopProxy的基础上优化了生成代理对象的效率。
JdkDynamicAopProxy生成代理类的效率高于CglibAopProxy , 但是生成的代理对象的执行效率是CglibAopProxy高,因此如果生成的代理类是单例的尽量使用ObjenesisCglibAopProxy来作为生成代理的方式, 如果是多例的就尽量使用JdkDynamicAopProxy来作为生成代理类的方式。
6、 ProxyFactory类:根据AOP配置生成代理类以及对象
在第4点中我们对SpringAOP的Advised、ProxyConfig整体类结构有一个明确的认识,接下来我们就来一 一剖析。
ProxyFactory名称叫代理工厂,作用就是根据AOP配置来生成代理类。
使用案例:
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
BeforeAdvice beforeAdvice = new UserServiceRegistryBeforeAdvice();
AfterReturningAdvice afterReturningAdvice = new UserviceRegistryAfetrReturnAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
/*
可添加多个增强,形成增强链,调用顺序跟添加顺序一致,
也可以使用proxyFactory.addAdvice(1, beforeAdvice);来指定位置。
*/
proxyFactory.addAdvice(1, beforeAdvice);
proxyFactory.addAdvice(beforeAdvice);
proxyFactory.addAdvice(afterReturningAdvice);
proxyFactory.setTarget(userService);
/*
设置接口类型的话,将会默认使用jdk的动态代理JdkDynamicAopProxy来创建代理对象。
否在会使用CGLIB动态代理ObjenesisCglibAopProxy来创建代理类,虽然是使用ObjenesisCglibAopProxy
来创建代理类,但是核心还是 其父类CglibAopProxy来控制,只是使用ObjenesisCglibAopProxy提供的
Objenesis创建对象的技术来创建代理类而已。!!!!!!!!!
*/
proxyFactory.setInterfaces(userService.getClass().getInterfaces());
/*
除此之外可以使用proxyFactory.setOptimize(true)来启动优化代理方式,设置为true的话
如果代理的Target有接口,也会使用CGLIB来创建代理类。
*/
proxyFactory.setOptimize(true);
UserService userServiceProxy = (UserService) proxyFactory.getProxy();
userServiceProxy.registryUser("张三");
}
实现原理分析:
主要的方法是proxyFactory.getProxy();
源码:
public Object getProxy() {
return createAopProxy().getProxy();
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) { active默认是false
activate();
}
//getAopProxyFactory()不做设置的话会使用默认的AopProxyFactory即DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
DefaultAopProxyFactory中的createAopProxy方法
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
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);
}
}
上面我们使用到了AopProxyFactory 其源码:
public interface AopProxyFactory {
/**
* Create an {@link AopProxy} for the given AOP configuration.
* @param config the AOP configuration in the form of an
* AdvisedSupport object
* @return the corresponding AOP proxy
* @throws AopConfigException if the configuration is invalid
*/
通过AOP的配置获取一个AopProxy(用于生成代理类以及代理对象)AdvisedSupport 实现了 Advised+ProxyConfig
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}
AopProxyFactory的实现目前只有一个那就是DefaultAopProxyFactory其源码:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
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);
}
}
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 &&
SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
7、ProxyFactoryBean : 根据AOP配置生成代理类以及代理对象
ProxyFactoryBean 类实现了Spring的FactoryBean<T> ,如果配置在spring ioc容器中,那么在容器装载的时候会调用其 getObject()方法,ProxyFactoryBean中的getObject()就是根据AOP配置然后生成代理实例返回。
使用案例:基于XML配置
<!--ProxyFactoryBean 使用之前置增强 beforeAdvice-->
<!--1、定义目标bean-->
<bean id="target" class="com.wzy.springstudy.aop.advice.impl.UserServiceImpl"/>
<!--2、定义增强bean-->
<bean id="berforeAdvice" class="com.wzy.springstudy.aop.advice.UserServiceRegistryBeforeAdvice"/>
<!--3、定义所需生成的代理类 使用实现了FactoryBean接口的ProxyFactoryBean-->
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--指定目标类-->
<property name="target" ref="target"/>
<!--指定生成的代理类需要实现那些接口。-->
<property name="proxyInterfaces" value="com.wzy.springstudy.aop.advice.UserService"/>
<!--指定需要植入连接点的增强多个增强名称使用“,”号隔开。-->
<property name="interceptorNames" value="berforeAdvice"/>
<!--是否启用代理优化设置为true将会强制使用CGLIB动态代理,
CGLIB创建代理类比较慢,但是创建的代理对象运行的效率
较高,跟jdk动态代理刚好相反,如果代理类是代理的,尽
量使用CGLIB来生成代理类-->
<property name="optimize" value="true"/>
<!--是否对类进行代理,如果设置为true将会使用CGLIB生成代理类。-->
<property name="proxyTargetClass" value="true"/>
<!--生成的代理类是否为单例,默认为true-->
<property name="singleton" value="true"/>
<!--是否暴露生成的代理对象,默认为false,设置为true 可以
在目标类的被增强的连接点(方法)中使用AopContext.currentProxy()
来获取当前生成的代理实例。-->
<property name="exposeProxy" value="true"/>
</bean>
实现原理分析:我们主要来分析ProxyFactoryBean中的getObject()方法。
源码:
public Object getObject() throws BeansException {
初始化切面的链,就是将配置的interceptorNames 按顺序初始化切面bean
initializeAdvisorChain();
if (isSingleton()) {
如果是单例bean就去获取一个单实例,实际是就是去创建代理实例
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
如果是多例bean就直接创建代理对象
return newPrototypeInstance();
}
}
获取单实例的代理实例
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
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");
}
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
创建一个AopProxyFactory然后构建代理实例
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
创建一个AopProxy 这里跟ProxyFactory的实现是一样的,都是继承ProxyCreatorSupport
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
protected Object getProxy(AopProxy aopProxy) {
使用创建的AopProxy来构建代理实例
return aopProxy.getProxy(this.proxyClassLoader);
}
8、AspectJProxyFactory:根据Aspectj的配置AOP生成代理实例
SpringAOP支持使用AspectJ来配置切面,然后使用AspectJProxyFactory来根据AspectJ配置的AOP来生成代理实例。
AspectJ的基础配置:主要使用的注解:
@Before、@After、@Around、@Pointcut、@Aspect
AspectJ就是使用上述注解来进行切面的配置。
使用案例:
定义目标类
public class AspectJTarget {
public void test(){
System.out.println("AspectJTarget...");
}
}
定义切面类
@Aspect
public class AspectJTestBean {
@Before(value = "execution(* com.wzy.springstudy.aop.AspectJ.c.*.test())")
public void before(){
System.out.println("before");
}
测试代码
public static void main(String[] args) {
AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory();
设置目标类
aspectJProxyFactory.setTarget(new AspectJTarget());
添加Aspect实例 注意此实例的类一定需要使用@Aspect注解标注
aspectJProxyFactory.addAspect(new AspectJTestBean());
使用AspectJProxyFactory 来构建代理实例
AspectJTarget proxy = aspectJProxyFactory.getProxy();
使用代理类调用业务方法
proxy.test();
}
}
输出结果
before
AspectJTarget...
实现原理分析:AspectJProxyFactory的getProxy()方法跟ProxyFactory、ProxyFactoryBean都是一样的实现,此处我们就不过多描述,我们主要关注的是AspectJProxyFactory是如何解析AspectJ的AOP配置的。所以我们主要看
aspectJProxyFactory.addAspect(new AspectJTestBean()); 这个的实现
源码:
public void addAspect(Object aspectInstance) {
Class<?> aspectClass = aspectInstance.getClass();
String aspectName = aspectClass.getName();
获取AspectJ的注解数据
AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
校验注解数据是否符合正常的AspectJ的配置
if (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) {
throw new IllegalArgumentException(
"Aspect class [" + aspectClass.getName() + "] does not define a singleton aspect");
}
解析切面并添加到AOP配置中
addAdvisorsFromAspectInstanceFactory(
new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName));
}
解析切面并添加到AOP配置中
private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) {
使用aspectFactory来解析AspectJ配置生成切面Advisor,aspectFactory默认是等于private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();的
List<Advisor> advisors = this.aspectFactory.getAdvisors(instanceFactory);
advisors = AopUtils.findAdvisorsThatCanApply(advisors, getTargetClass());
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
AnnotationAwareOrderComparator.sort(advisors);
将通过AspectJ配置生成好的切面添加到AOP配置中,因为AspectJProxyFactory实现了Advised、ProxyConfig接口,所以可以进行此操作。
addAdvisors(advisors);
}
使用ReflectiveAspectJAdvisorFactory来将AspectJ的配置实例解析成为Advisor
ReflectiveAspectJAdvisorFactory 此类的作用就是解析AspectJ的注解来解析成为Advisor切面。此处篇幅太大,所以自行查看其源码。
结论:AspectJProxyFactory的实现其实就是使用ReflectiveAspectJAdvisorFactory来解析AspectJ的配置生成Advisor切面,然后使用这些切面来构建代理实例。
9、整体总结:
1、本篇博客主要讲了SpringAOP的增强Advice接口、Pointcut(切点接口)、Advisor(切面接口)、Advised\ProxyConfig(代理配置接口)、AopProxy(构建代理类的接口jdk\cglib)、AopProxyFactory(用于创建AopProxy实例的接口)。
2、其次我们讲解了根据AOP配置来构建代理实例的代理构建器:
ProxyFactory
ProxyFactoryBean
AspectJProxyFactory
以上三个代理构建器都是费全自动的代理构建器,在后面章节我们会涉及到SpringAOP的自动代理构建器AbstractAutoProxyCreator。