AOP都知道,是spring中的面向切面編程,就是可以把我們寫的代碼橫向擴展,而且又不會影響原來的代碼結構,是一種思想。說白了就是可以在你想實現什麼功能的前後能夠搞一些事情。底層使用的是JDK和Cglib動態代理
爲什麼要使用AOP呢:
1、AOP採用了橫向的抽取機制,取代了傳統縱向繼承體系重複性代碼結構
2、可以在不修改源代碼的前提下,對程序功能進行增強
主要的幾種的方式:
1、前置通知:@Before 在我們執行目標方法前運行
2、後置通知:@After 在我們目標方法運行之後運行,不管有沒有異常
3、後置返回通知:@AfterReturning 在我們的目標方法正常返回值之後運行
4、異常通知:@AfterThrowing 在我們執行目標方法出現異常之後運行
5、環繞通知:@Around 前置 > @Before +後置 < @After(正常) 動態代理,必須手動執行目標方法
註解實現AOP
先創建一個Service和接口類
public interface UserService {
public String selectUserName();
}
@Service("userService")
public class UserServiceImp implements UserService {
@Override
public String selectUserName() {
String name = "zx";
return name;
}
}
創建實體類
public class UserEntity {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
創建一個控制層
@RestController
@RequestMapping("/aop")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/aoptest")
public void UserTest(){
System.out.println("UserServiceImp方法");
userService.selectUserName();
}
}
創建代理的配置類。把bean注入到容器中
@Configuration
@EnableAspectJAutoProxy
public class UserConfig{
/**
* 把目標類註冊到spring容器中去
* @return
*/
@Bean
public UserService userService(){
return new UserService() {
@Override
public String selectUserName() {
String name = "配置類實例";
return name;
}
};
}
/**
* 註冊切面類到spring容器中去
* @return
*/
@Bean
public UserPointCut servantAspects02(){
return new UserPointCut();
}
}
再創建一個切面類
@Aspect
@Component
public class UserPointCut {
@Pointcut("execution(* com.zx.springaop.service..*(..))")
public void UserPointCut(){}
@Before("UserPointCut()")
public void BeforUser(){
System.out.println("前置");
}
@After("UserPointCut()")
public void AfterUser(){
System.out.println("後置");
}
@AfterReturning("UserPointCut()")
public void AfterReturning(){
System.out.println("後置返回");
}
@AfterThrowing(value = "UserPointCut()",throwing = "ex")
public void AfterThreadExction(Exception ex){
System.out.println("後置異常拋出"+ex);
}
@Around("UserPointCut()")
public Object AroudUserCut(ProceedingJoinPoint pjd) {
Object result=null;
String methodName=pjd.getSignature().getName();//方法名
try {
//前置通知
System.out.println("the method "+methodName+" begins with "+Arrays.asList(pjd.getArgs()));
result=pjd.proceed();
//結果通知
System.out.println("the method"+methodName+" ends "+result);
} catch (Throwable e) {
//異常通知
System.out.println("the method "+methodName+" occurs execption:"+e);
throw new RuntimeException(e);
}
//後置通知
System.out.println("the method "+methodName+" ends");
return result;
}
}
最後創建一個測試類
public class UserPointCutTest {
public static void main(String args[]){
AnnotationConfigApplicationContext acc = new AnnotationConfigApplicationContext(UserConfig.class);
UserService userService = (UserService) acc.getBean(UserService.class);
userService.selectUserName();
}
}
輸出:
——————————————————————————————
下面開始分析。
打斷點,看debug模式,
可以看到現在是JDK的動態代理模式,那麼怎麼可以轉變成CGLib呢,
狀態改爲true就是強制使用CGLib動態代理了。說白了就是把有沒有接口。有接口就是JDK,沒有就默認CGLib
流程分析:
將bean導入spring容器AspectJAutoProxyRegistrar->ImportBeanDefinitionRegistrar#registerBeanDefinitions
將bean註冊到spring容器 AnnotationAwareAspectJAutoProxyCreator className: org.springframework.aop.config.internalAutoProxyCreator class: 根據spring提供的規範構建spring bean RootBeanDefinition
上面構建 AnnotationAwareAspectJAutoProxyCreator 這個bean 然後這個bean實現InstantiationAwareBeanPostProcessor接口
該接口實現BeanPostProcessor接口 BeanPostProcessor是spring提供的擴展接口 在bean實例的時候回調 --》postProcessAfterInitialization
然後就會找所有的Advisor
1、 第一步: 先找父類時候有實現Advisor的接口。
2、 第二步: 然後找到所有類上面註解標註爲@Aspect, 然後解析該類標註Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
AOP的 實現方式很簡單,就是動態代理。就是在實例化的時候生成代理類,來替換掉真實實現類來對外提供服務。就是在getBean(…)的時候返回的其實是代理類的一個實例,而這個代理類就是JDK活着CGLib動態生成的,(spring-aop只能在Spring中才能實現。)
先看一下 DefaultAdvisorAutoProxyCreator類中的BeanPostProcessor方法。在IOC中,這個方法是在init-method前後執行的。
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
回顧一下IOC:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 1. 創建實例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 2. 裝載屬性
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 3. 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
...
}
在第三步,初始化Bean,會調用BeanPostProcessor()方法
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
...
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 1. 執行每一個 BeanPostProcessor 的 postProcessBeforeInitialization 方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 調用 bean 配置中的 init-method="xxx"
invokeInitMethods(beanName, wrappedBean, mbd);
}
...
if (mbd == null || !mbd.isSynthetic()) {
// 我們關注的重點是這裏!!!
// 2. 執行每一個 BeanPostProcessor 的 postProcessAfterInitialization 方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
也就是說,Spring AOP 會在 IOC 容器創建 bean 實例的最後對 bean 進行處理。其實就是在這一步進行代理增強。
DefaultAdvisorAutoProxyCreator 的繼承結構中,postProcessAfterInitialization() 方法在其父類 AbstractAutoProxyCreator 這一層被覆寫了:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
看wrapifnecessary方法。會返回一個代理類
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 返回匹配當前 bean 的所有的 advisor、advice、interceptor
// 對於本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 這兩個 bean 創建過程中,
// 到這邊的時候都會返回兩個 advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 創建代理...創建代理...創建代理...
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
在看 createProxy(…)方法,創建代理類:
// 注意看這個方法的幾個參數,
// 第三個參數攜帶了所有的 advisors
// 第四個參數 targetSource 攜帶了真實實現的信息
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 創建 ProxyFactory 實例
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 在 schema-based 的配置方式中,我們介紹過,如果希望使用 CGLIB 來代理接口,可以配置
// proxy-target-class="true",這樣不管有沒有接口,都使用 CGLIB 來生成代理:
// <aop:config proxy-target-class="true">......</aop:config>
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 點進去稍微看一下代碼就知道了,主要就兩句:
// 1. 有接口的,調用一次或多次:proxyFactory.addInterface(ifc);
// 2. 沒有接口的,調用:proxyFactory.setProxyTargetClass(true);
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 這個方法會返回匹配了當前 bean 的 advisors 數組
// 對於本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 到這邊的時候都會返回兩個 advisor
// 注意:如果 specificInterceptors 中有 advice 和 interceptor,它們也會被包裝成 advisor,進去看下源碼就清楚了
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
這個方法主要是在內部創建了一個 ProxyFactory 的實例,然後 set 了一大堆內容,剩下的工作就都是這個 ProxyFactory 實例的了,通過這個實例來創建代理: getProxy(classLoader)。
看看代理類
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
通過創建代理類來生成aop代理
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
創建 AopProxy 之前,我們需要一個 AopProxyFactory 實例,然後看 ProxyCreatorSupport 的構造方法:
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
看DefaultAopProxyFactory 這個類,我們看它的 createAopProxy(…) 方法:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// (我也沒用過這個optimize,默認false) || (proxy-target-class=true) || (沒有接口)
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.");
}
// 如果要代理的類本身就是接口,也會用 JDK 動態代理
// 我也沒用過這個。。。
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
// 如果有接口,會跑到這個分支
return new JdkDynamicAopProxy(config);
}
}
// 判斷是否有實現自定義的接口
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}
這就有可能返回jdk,也有可能返回cglib,然後下面就分別是jdk和cglib的源碼,最後各自集成各自的攔截類,進行代理