以简单的例子为例说明aop的流程,源码如下:
package com.renlijia;
import com.AppWebConfig;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @Author: ding
* @Date: 2020-06-06 13:02
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class AppStart {
public static void main(String[] args) throws Exception{
SpringApplication springApplication = new SpringApplication(AppWebConfig.class);
ConfigurableApplicationContext context = springApplication.run(args);
}
}
package com;
import com.renlijia.annotation.Test1;
import com.renlijia.controller.Student;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.*;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
* @Author: ding
* @Date: 2021-01-18 13:15
*/
@ComponentScan(basePackages = {"com"})
@Configuration
@EnableAutoConfiguration
@EnableAspectJAutoProxy
@ServletComponentScan
@EnableWebMvc
@Import(Student.class)
public class AppWebConfig {
}
package com.renlijia.controller;
import com.dxc.MyEnum;
import com.google.common.collect.Maps;
import com.renlijia.config.MyConfig;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.AutoProxyRegistrar;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Array;
import java.text.MessageFormat;
import java.util.Map;
/**
* @Author: ding
* @Date: 2020-12-08 09:57
*/
@Controller
public class TestController {
@Autowired
private Person person;
@Autowired
private Student student;
@Autowired
private GenericApplicationContext applicationContext;
@Autowired
private ResourceLoader resourceLoader;
@Autowired
private DispatcherServlet dispatcherServlet;
@Autowired
private Environment environment;
@Autowired
private BeanFactory beanFactory;
@Autowired
private MyConfig myConfig;
private String name = "2222";
@RequestMapping("/initBillData")
public String initBillData(HttpServletRequest request, HttpServletResponse response) throws Exception{
//request.getRequestDispatcher("/forward").forward(request,response);
return "dxc.htm";
}
@RequestMapping("/redirect")
public String redirect(HttpServletRequest request, HttpServletResponse response) throws Exception{
response.sendRedirect("/forward");
return "有兴趣来我们公司吗?";
}
@RequestMapping("/forward")
@ResponseBody
public User forward(HttpServletRequest request, HttpServletResponse response) throws Exception{
User user = new User();
user.setAge(100);
return user;
}
@RequestMapping("/f1")
@ResponseBody
public User f1() throws Exception{
MyEnum.getInstance().setAge(110000);
System.out.println(environment.getProperty("java.runtime.name"));
final TestController testController = applicationContext.getBean(TestController.class);
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
MetadataReaderFactory metaReader = new CachingMetadataReaderFactory(resourceLoader);
org.springframework.core.io.Resource[] resources = resolver.getResources("classpath*:com/renlijia/**/*.class");
for (org.springframework.core.io.Resource r : resources) {
MetadataReader reader = metaReader.getMetadataReader(r);
System.out.println(reader.getClassMetadata().getClassName());
}
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
request.getSession();
User user = new User();
user.setAge(100);
user.setUserId("123455533");
return user;
}
@RequestMapping("/f2")
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
Map<String, String> model = Maps.newHashMap();
model.put("param1", "22222");
return new ModelAndView("dxc.htm", model);
}
public static void main(String[] args) {
System.out.println(AutoProxyRegistrar.class.getName());
}
}
package com.renlijia;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* @Author: ding
* @Date: 2021-02-06 21:33
*/
@Aspect
@Component
public class AdviceTest {
@Pointcut("execution(public * com.renlijia.controller.TestController.*(..))")
public void pointCut() {
}
@AfterReturning(pointcut="pointCut()", returning="returnValue")
public void log(JoinPoint point, Object returnValue) {
System.out.println("@AfterReturning:模拟日志记录功能...");
System.out.println("@AfterReturning:目标方法为:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@AfterReturning:参数为:" +
Arrays.toString(point.getArgs()));
System.out.println("@AfterReturning:返回值为:" + returnValue);
System.out.println("@AfterReturning:被织入的目标对象为:" + point.getTarget());
}
@After(value = "pointCut()")
public void releaseResource(JoinPoint point) {
System.out.println("@After:模拟释放资源...");
System.out.println("@After:目标方法为:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@After:参数为:" + Arrays.toString(point.getArgs()));
System.out.println("@After:被织入的目标对象为:" + point.getTarget());
}
}
这个例子很简单,就是在调用TestController所有方法之前和返回后打印一些信息,来分析下整个aop的流程,首先开启aop是通过EnableAspectJAutoProxy完成,EnableAspectJAutoProxy注解的内容为:
![](https://img.haomeiwen.com/i18396224/cf375aa82b272187.png)
所以真正加载的是AspectJAutoProxyRegistrar,然后我们进入这个类去看:
![](https://img.haomeiwen.com/i18396224/27e05503d339b7fd.png)
核心是调用AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);注册,一层层进入,最后看到的是这块代码:
![](https://img.haomeiwen.com/i18396224/13f1e86994d20a66.png)
这个代码很简单,就是先判断系统有没有AUTO_PROXY_CREATOR_BEAN_NAME这个bean,有的话根据优先级去加载,如果没有则创建beanDefinition,这个class是AnnotationAwareAspectJAutoProxyCreator,查看一下该类的继承关系图:
![](https://img.haomeiwen.com/i18396224/bcce763e90cef0ac.png)
所以该类是BeanPostProcessor接口的实现类,该接口有两个方法:
![](https://img.haomeiwen.com/i18396224/dff89acc26beff5c.png)
实现这个接口的类,所有bean在初始化前后就会调用,我们看看AnnotationAwareAspectJAutoProxyCreator实现这两个接口的地方:
![](https://img.haomeiwen.com/i18396224/c08d4598e0dc6f21.png)
postProcessAfterInitialization这个是核心,每个bean初始化后会走到这里,这个方法会调用包装方法wrapIfNecessary
![](https://img.haomeiwen.com/i18396224/40c33b5a8dc40681.png)
这个方法的功能是对bean进行包装,如果该bean不需要包装,则直接返回原bean,满足需要包装的条件去看getAdvicesAndAdvisorsForBean方法,该方法最后调用的是这块代码
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();
}
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
这块代码的逻辑是,先查询Advisors,在例子中有两个advisors,断点查看
![](https://img.haomeiwen.com/i18396224/4003ffc0829aa3b4.png)
就是AdviceTest切面中的两个切点,findAdvisorsThatCanApply功能是找到切点满足该bean匹配条件的Advisors,因为这两个切点配置的正则表达式com.renlijia.controller.TestController.*(..)),所以对于TestController这个bean,返回的就是这两个Advisors,回到wrapIfNecessary代码块,如果返回的满足条件的Advisors不为空,则对该bean进行代理,代理代码:
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
根据配置的参数,会使用jdk或者cglib进行代理的生成,是否使用jdk还是cglib根据注解EnableAspectJAutoProxy中的proxyTargetClass决定:
![](https://img.haomeiwen.com/i18396224/9efd8d961a0be3e8.png)
选择代理方式的代码:
@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);
}
}
JdkDynamicAopProxy其实就是对应jdk代理的InvocationHandler,初步的分析到此,下一步分析代理中的执行的具体逻辑。
网友评论