spring隨筆(AOP)

AOP術語

1.target:目標類,需要被代理的類。例如:UserService
2.Joinpoint(連接點):所謂連接點是指那些可能被攔截到的方法。例如:所有的方法
3**.PointCut** 切入點:已經被增強的連接點。例如:addUser()
4.advice 通知/增強,增強代碼。例如:after、before
5 . Weaving(織入):是指把增強advice應用到目標對象target來創建新的代理對象proxy的過程.
6.proxy 代理類
7 . Aspect(切面): 是切入點pointcut和通知advice的結合,一個切入點和一個通知,組成成一個特殊的面。

cglib

package com.spring.cglb;
//切面類
public class MyAspect {
    public void before() {
        System.out.println("開啓事物");
    }

    public void after() {
        System.out.println("提交事務");
    }

}
package com.spring.cglb;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Service;

@Service
public class MyBeanFactory {
    public static UserServiceImpl getServiceInstance() {
        final MyAspect aspect = new MyAspect();
        final UserServiceImpl userService = new UserServiceImpl();
        Enhancer e = new Enhancer();
        e.setSuperclass(userService.getClass());
        //回調函數
        e.setCallback(new MethodInterceptor() {

            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy proxymethod)
                    throws Throwable {
                aspect.before();
                Object obj = method.invoke(userService, args);
                aspect.after();
                return obj;
            }
        });
        // 創建代理類
        UserServiceImpl proxyService = (UserServiceImpl) e.create();
        return proxyService;
    }
}

AOP聯盟通知類型

AOP聯盟爲通知Advice定義了org.aopalliance.aop.Advice
Spring按照通知Advice在目標類方法的連接點位置,可以分爲5類
前置通知 org.springframework.aop.MethodBeforeAdvice
在目標方法執行前實施增強
後置通知 org.springframework.aop.AfterReturningAdvice
在目標方法執行後實施增強
環繞通知 org.aopalliance.intercept.MethodInterceptor
在目標方法執行前後實施增強
異常拋出通知 org.springframework.aop.ThrowsAdvice
在方法拋出異常後實施增強
引介通知 org.springframework.aop.IntroductionInterceptor
在目標類中添加一些新的方法和屬性

Aop半自動代理

package com.spring.semiauto;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

//切面類 在切面l類中確定通知類型  實現不同的接口 使用環繞通知 

public class MyAspect implements MethodInterceptor {
    public void before() {
        System.out.println("開啓事物");
    }

    public void after() {
        System.out.println("提交事務");
    }

    @Override
    public Object invoke(MethodInvocation m) throws Throwable {
        this.before();
        // 手動執行目標方法
        Object obj = m.proceed();
        this.after();
        return obj;
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- target類 -->
    <bean id="UserServiceId" class="com.spring.semiauto.UserServiceImpl"></bean>
    <!-- 切面類 -->
    <bean id="MyAspect" class="com.spring.semiauto.MyAspect"></bean>
    <!-- 創建代理類
       使用工廠bean FractoryBean,底層調用getObjiect() ,返回bean
       proxyFractoryBean 用於創建代理工廠 生成特殊代理對象
       interfaces   確定代理的接口們
       target          注入目標類
       interceptorNames  切面類名稱
       optimize :強制使用cglib
              底層的原理是:
              判斷有沒有接口 有接口使用jdk代理
              沒有接口使用cglib代理
              聲明optimize 使用cglib       

     -->

    <bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean" >
        <property name="interfaces" value="com.spring.semiauto.UserService"></property>
        <property name="target" ref="UserServiceId"></property>
        <property name="interceptorNames" value="MyAspect"></property>

    </bean>


</beans>

AOP自動代理

導入jar包:這裏寫圖片描述 切入點表達式jar
引入命名空間

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop 
         http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- target類 -->
    <bean id="UserService" class="com.spring.auto.UserServiceImpl"></bean>
    <!-- 切面類 -->
    <bean id="MyAspect" class="com.spring.auto.MyAspect"></bean>
    <!-- aop編程 -->
    <aop:config>
    <aop:pointcut expression="execution(* com.spring.auto.UserServiceImpl.*(..))" id="Mypoincut"/>
    <aop:advisor advice-ref="MyAspect" pointcut-ref="Mypoincut"/>
    </aop:config>
</beans>

AspectJ

aspectj 通知類型

before:前置通知(應用:各種校驗)
在方法執行前執行,如果通知拋出異常,阻止方法運行
afterReturning:後置通知(應用:常規數據處理)
方法正常返回後執行,如果方法中拋出異常,通知無法執行
必須在方法執行後才執行,所以可以獲得方法的返回值。
around:環繞通知(應用:十分強大,可以做任何事情)
方法執行前後分別執行,可以阻止方法的執行必須手動執行目標方法
afterThrowing:拋出異常通知(應用:包裝異常信息)
方法拋出異常後執行,如果方法沒有拋出異常,無法執行
after:最終通知(應用:清理現場)
方法執行完畢後執行,無論方法中是否出現異常

aspectj編程

這裏寫圖片描述

package com.spring.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

//切面類
public class MyAspect {
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("前置通知:" + "方法名。。。。" + name);
    }

    public void afterReturning(JoinPoint jp, Object ret) {
        System.out.println("後置通知");
        System.out.println(ret);

    }

    public void after(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("最終通知:" + "方法名。。。。" + name);
    }

    public Object MyArround(ProceedingJoinPoint pjp, Object ret) throws Throwable {
        this.before(pjp);
        Object object = pjp.proceed();
        this.afterReturning(pjp, ret);
        return object;
    }

    public void MyAfterThrowable(JoinPoint jp, Throwable e) {
        String name = jp.getSignature().getName();
        System.out.println("異常:" + name + "..." + e.getMessage());

    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop 
         http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 目標類 -->
    <bean id="UserService" class="com.spring.aspectj.UserServiceImpl"></bean>
    <!-- 切面類 -->
    <bean id="MyAspect" class="com.spring.aspectj.MyAspect"></bean>

    <!-- 前置通知配置 ref 引入切面 pointcut 切入點表達式 此表達式只能當前通知使用 pointcut 切入點引用 可與其他通知共享 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut
                expression="execution(* 
        com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:before method="before" pointcut-ref="Mypointcut" />
        </aop:aspect>
    </aop:config>
    <!-- 最終通知 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut
                expression="execution(* 
        com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:after method="after" pointcut-ref="Mypointcut" />
        </aop:aspect>
    </aop:config>
    <!-- 環繞通知 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:around method="MyArround" pointcut-ref="Mypointcut" />
        </aop:aspect>
    </aop:config>
    <!-- 異常通知 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:after-throwing method="MyAfterThrowable"
                pointcut-ref="Mypointcut" throwing="e" />
        </aop:aspect>
    </aop:config>
    <!-- 後置通知 -->
    <aop:config>
        <aop:aspect ref="MyAspect">
            <aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
                id="Mypointcut" />
            <aop:after-returning method="afterReturning"
                pointcut-ref="Mypointcut" returning="ret" />

        </aop:aspect>
    </aop:config>


</beans>

使用註解

//切面類
@Component
@Aspect
public class MyAspect {
    //創建切入點表達式
    @Pointcut("execution(* com.spring.aop_annotation.UserServiceImpl.*(..))")
    public void MyPointCut() {

    }

    @Before("MyPointCut()")
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("前置通知:" + "方法名。。。。" + name);
    }

    @AfterReturning(value = "MyPointCut()", returning = "ret")
    public void afterReturning(JoinPoint jp, Object ret) {
        System.out.println("後置通知");
        System.out.println(ret);

    }

    @After("MyPointCut()")
    public void after(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println("最終通知:" + "方法名。。。。" + name);
    }

    @Around("MyPointCut()")
    public Object MyArround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("前");
        Object object = pjp.proceed();
        System.out.println("後");
        return object;
    }

    @AfterThrowing(value = "MyPointCut()", throwing = "e")
    public void MyAfterThrowable(JoinPoint jp, Throwable e) {
        String name = jp.getSignature().getName();
        System.out.println("異常:" + name + "..." + e.getMessage());

    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.spring.aop_annotation"></context:component-scan>
    <!-- 使aop註解生效 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章