spring 筆記2 aop

AOP

什么是AOP

  • 在軟件業(yè)票罐,AOP為Aspect Oriented Programming的縮寫(xiě)笑旺,意為:面向切面編程量承,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)题禀。AOP是OOP的延續(xù)鞋诗,是軟件開(kāi)發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容迈嘹,是函數(shù)式編程的一種衍生范型削彬。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離全庸,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性融痛,同時(shí)提高了開(kāi)發(fā)的效率壶笼。
  • AOP 采取橫向抽取機(jī)制,取代了傳統(tǒng)縱向繼承體系重復(fù)性代碼雁刷。
  • 經(jīng)典應(yīng)用:事物管理覆劈,性能監(jiān)視,安全檢查安券,緩存墩崩,日志等。
  • Spring AOP 使用純java實(shí)現(xiàn)侯勉,不需要專(zhuān)門(mén)的編譯過(guò)程和類(lèi)加載器鹦筹,在運(yùn)行期通過(guò)代理方式向目標(biāo)類(lèi)織入增強(qiáng)代碼
  • AspectJ是一個(gè)基于Java語(yǔ)言的AOP框架,Spring2.0開(kāi)始址貌,Spring AOP引入對(duì)Aspect的支持铐拐,AspectJ擴(kuò)展了Java語(yǔ)言,提供了一個(gè)專(zhuān)門(mén)的編譯器练对,在編譯時(shí)提供橫向代碼的織入

AOP實(shí)現(xiàn)原理

  • aop 底層將采用代理機(jī)制進(jìn)行實(shí)現(xiàn)遍蟋。
  • 接口 + 實(shí)現(xiàn)類(lèi):spring采用jdk的動(dòng)態(tài)代理proxy。
  • 實(shí)現(xiàn)類(lèi):spring采用cglib字節(jié)碼增強(qiáng)螟凭。

AOP術(shù)語(yǔ)

  • 1.target:目標(biāo)類(lèi)虚青,需要被代理的類(lèi)。例如:UserService螺男。
  • 2.Joinpoint(連接點(diǎn)):所謂連接點(diǎn)是指那些可能被攔截到的方法棒厘。例如:所有的方法。
  • 3.PointCut 切入點(diǎn):已經(jīng)被增強(qiáng)的連接點(diǎn)下隧。例如:addUser()奢人。
  • 4.advice 通知/增強(qiáng),增強(qiáng)代碼淆院。例如:after何乎、before。
    1. Weaving(織入):是指把增強(qiáng)advice應(yīng)用到目標(biāo)對(duì)象target來(lái)創(chuàng)建新的代理對(duì)象proxy的過(guò)程.
  • 6.proxy 代理類(lèi)土辩。
    1. Aspect(切面): 是切入點(diǎn)pointcut和通知advice的結(jié)合支救。
aop1.png

手動(dòng)方式

JDK動(dòng)態(tài)代理

  • JDK動(dòng)態(tài)代理 對(duì)“裝飾者”設(shè)計(jì)模式 簡(jiǎn)化。使用前提:必須有接口
    1.目標(biāo)類(lèi):接口 + 實(shí)現(xiàn)類(lèi)
    2.切面類(lèi):用于存通知 MyAspect
    3.工廠類(lèi):編寫(xiě)工廠生成代理
目標(biāo)類(lèi)
public interface UserService {
    void addUser();
    void updateUser();
    void deleteUser();
}

public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("------addUser");
    }

    @Override
    public void updateUser() {
        System.out.println("------updateUser");
    }

    @Override
    public void deleteUser() {
        System.out.println("------deleteUser");

    }
}
切面類(lèi)
public class MyAspect {
    public void before(){
        System.out.println("方法之前");
    }

    public void after(){
        System.out.println("方法之后");

    }
}
工廠類(lèi)
public class MyBeanFactory {
    public static UserService createService() {
        final UserService userService = new UserServiceImpl();
        final MyAspect myAspect = new MyAspect();
        /**
         * Proxy.newProxyInstance
         * 參數(shù)1:loader 類(lèi)加載器,動(dòng)態(tài)代理類(lèi) 運(yùn)行時(shí)創(chuàng)建,任何類(lèi)都需要類(lèi)加載器加載到內(nèi)存
         *      一般情況:當(dāng)前類(lèi).getClassLoader();
         *              目標(biāo)類(lèi)實(shí)例.getClass.getClassLoader()
         * 參數(shù)2: Class[] interfaces代理類(lèi)需要實(shí)現(xiàn)所有的接口
         *      方式1:目標(biāo)類(lèi)實(shí)例.getClass().getInterfaces();只能獲得自己接口,不能獲得父元素接口
         *      方式2:new Class[]{...}
         * 參數(shù)3:InvocationHandler 處理類(lèi),接口必須進(jìn)行實(shí)現(xiàn)類(lèi),一般采用匿名內(nèi)部
         *      提供invoke 方法,代理類(lèi)的每一個(gè)方法執(zhí)行,都將調(diào)用一次invoke
         *      參數(shù)1:Object proxy:代理對(duì)象
         *      參數(shù)2:Mehod method:代理對(duì)象當(dāng)前執(zhí)行的方法描述對(duì)象(反射)
         *              執(zhí)行方法名:method.getName()
         *              執(zhí)行方法:method.invoke(對(duì)象,實(shí)際參數(shù))
         *      參數(shù)3:Object[] args:方法實(shí)際參數(shù)
         *
         */

        UserService proxService = (UserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
                userService.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        myAspect.before();
                        Object  obj = method.invoke(userService,args);
                        myAspect.after();
                        return obj;
                    }
                });

        return proxService;
    }
}

CGLIB 字節(jié)碼增強(qiáng)

  • 沒(méi)有接口拷淘,只有實(shí)現(xiàn)類(lèi)搂妻。
  • 采用字節(jié)碼增強(qiáng)框架CGLIB,在運(yùn)行時(shí)創(chuàng)建目標(biāo)類(lèi)的子類(lèi)辕棚,從而對(duì)目標(biāo)類(lèi)進(jìn)行增強(qiáng)
實(shí)例
public class CGLIBFactory {

    public static UserServiceImpl createService() {
        //目標(biāo)類(lèi)
        UserServiceImpl userService;
        userService = new UserServiceImpl();
        //切面類(lèi)
        MyAspect myAspect = new MyAspect();


        //代理類(lèi)采用cglib 底層創(chuàng)建目標(biāo)類(lèi)的子類(lèi)
        //核心類(lèi)
        Enhancer enhancer = new Enhancer();
        //確定父類(lèi)
        enhancer.setSuperclass(userService.getClass());

        /**
         * 設(shè)置回調(diào)函數(shù),MethodInterceptor 接口等效 jdk InvocationHandler接口
         * intercept 等效jdk invoke()
         * 參數(shù)4:methodProxy 方法的代理
         */
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                myAspect.before();
               Object obj =  method.invoke(userService,args);
                myAspect.after();


                return obj;
            }
        });

        //創(chuàng)建代理類(lèi)
        UserServiceImpl proxService = (UserServiceImpl) enhancer.create();
        return  proxService;

    }

}

AOP聯(lián)盟通知類(lèi)型

AOP聯(lián)盟為通知Advice定義了org.aopalliance.aop.Advice

Spring按照通知Advice在目標(biāo)類(lèi)方法的連接點(diǎn)位置欲主,可以分為5類(lèi)

前置通知 org.springframework.aop.MethodBeforeAdvice
在目標(biāo)方法執(zhí)行前實(shí)施增強(qiáng)
后置通知 org.springframework.aop.AfterReturningAdvice
在目標(biāo)方法執(zhí)行后實(shí)施增強(qiáng)
環(huán)繞通知 org.aopalliance.intercept.MethodInterceptor
在目標(biāo)方法執(zhí)行前后實(shí)施增強(qiáng)
異常拋出通知 org.springframework.aop.ThrowsAdvice
在方法拋出異常后實(shí)施增強(qiáng)
引介通知 org.springframework.aop.IntroductionInterceptor
在目標(biāo)類(lèi)中添加一些新的方法和屬性
環(huán)繞通知邓厕,必須手動(dòng)執(zhí)行目標(biāo)方法
try{
   //前置通知
   //執(zhí)行目標(biāo)方法
   //后置通知
} catch(){
   //拋出異常通知
}

spring 編寫(xiě)代理:半自動(dòng)

  • 讓spring 創(chuàng)建代理對(duì)象,從spring容器中手動(dòng)的獲取代理代理對(duì)象
  • 需要jar包: aopallicance-1.0.0.jar ,spring-aop.release.jar
spring 配置
//目標(biāo)類(lèi)
 <bean id="userServiceId" class="cn.leyue.a_aop.c_spring.UserServiceImpl"></bean>
 //切面類(lèi)(通知)
 <bean id="myAspectId" class="cn.leyue.a_aop.c_spring.MyAspect"></bean>

    <!--
        創(chuàng)建代理類(lèi)
        * 使用工廠bean FactoryBean ,底層調(diào)用getObject()返回特殊bean
        * ProxyFactoryBean 用于創(chuàng)建代理工程bean,生成特殊代理對(duì)象,
            interfaces:確定接口們
                通過(guò)<array>可以設(shè)置多個(gè)值
                只有一個(gè)值時(shí),value=""
             target 確定目標(biāo)類(lèi)
                 interceptorNames:通知切面類(lèi)的名稱(chēng),類(lèi)型String[],如果設(shè)置一個(gè)值 value=""
             optimize:強(qiáng)制使用cglib
                 <property name="optimize" value="true"></property>
        * 底層機(jī)制
             如果目標(biāo)類(lèi)接口,采用jdk動(dòng)態(tài)代理
             如果沒(méi)有接口,采用cglib 字節(jié)碼增強(qiáng)
             如果生命optimize=true 無(wú)論是否有接口,都采用cglib

    -->
    <bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interfaces" value="cn.leyue.a_aop.c_spring.UserService"></property>
        <property name="target" ref="userServiceId"></property>
        <property name="interceptorNames" value="myAspectId"></property>
        <property name="optimize" value="true"></property>
    </bean>
目標(biāo)類(lèi)
public interface UserService {
    void addUser();
    void updateUser();
    void deleteUser();
}

public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("b_cglib------addUser");
    }

    @Override
    public void updateUser() {
        System.out.println("b_cglib------updateUser");
    }

    @Override
    public void deleteUser() {
        System.out.println("b_cglib------deleteUser");

    }
}
切面類(lèi)
/**
 * 切面類(lèi)中確定通知,需要實(shí)現(xiàn)不同接口,接口就是規(guī)范,從而確定方法名稱(chēng).
 * 采用"環(huán)繞通知"MethodInterceptor
 */
public class MyAspect implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("c_spring_方法之前");
        //手動(dòng)執(zhí)行目標(biāo)方法
        Object obj = methodInvocation.proceed();
        System.out.println("c_spring_方法之后");
        return obj;

    }

}
測(cè)試類(lèi)
public class SpringTest {
    @Test
    public void spring() {
        String path = "cn/leyue/a_aop/c_spring/beans.xml";
        ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
        UserService service = application.getBean("proxyServiceId", UserService.class);
        service.addUser();
        service.updateUser();
        service.deleteUser();
    }
}

spring aop編程:全自動(dòng)

  • 從spring 容器獲得目標(biāo)類(lèi)扁瓢,如何配置aop,spring將自動(dòng)生成代理
  • 要確定目標(biāo)類(lèi)详恼,aspectj切入點(diǎn)表達(dá)式,導(dǎo)入包引几。
    com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

spring 配置

導(dǎo)入命名空間
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
spring aop示例
<?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

        ">
    <!--目標(biāo)類(lèi)-->
    <bean id="userServiceId" class="cn.leyue.a_aop.d_spring_auto.UserServiceImpl"></bean>
    <!--切面類(lèi)通知-->
    <bean id="myAspectId" class="cn.leyue.a_aop.d_spring_auto.MyAspect"></bean>
    <bean id="proxyId" class="cn.leyue.a_aop.d_spring_auto.ProxyTest"></bean>

    <!--
        aop編程
        * 導(dǎo)入命名空間
        * 使用 <aop:config>進(jìn)行配置
        * proxy-target-class="true" 聲明時(shí)使用cglib代理
        * <aop:pointcut> 切入點(diǎn),從目標(biāo)對(duì)象獲得具體方法
        * <aop:advisor> 特殊的切面,只有一個(gè)通知和一個(gè)切入點(diǎn)
            advice-ref 通知引用
            pointcut-ref 切入點(diǎn)引用
        * 切入點(diǎn)表達(dá)式
            execution(*  cn.leyue.a_aop.d_spring_auto.*.*(..) )
            選擇方法 返回值任意             包      類(lèi)名任意  方法名任意 參數(shù)任意

    -->
    <aop:config proxy-target-class="true">
        <aop:pointcut id="myPointCut" expression="execution(* cn.leyue.a_aop.d_spring_auto.*.*(..))"></aop:pointcut>
        <aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"></aop:advisor>
    </aop:config>

</beans>`

目標(biāo)類(lèi)

public interface UserService {
    void addUser();
    void updateUser();
    void deleteUser();
}

public class UserServiceImpl implements UserService {

    @Override
    public void addUser() {
        System.out.println("d_spring_auto------addUser");
    }

    @Override
    public void updateUser() {
        System.out.println("d_spring_auto------updateUser");
    }

    @Override
    public void deleteUser() {
        System.out.println("d_spring_auto------deleteUser");

    }
}

切面類(lèi)

public class MyAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("d_spring_auto_方法之前");
        //手動(dòng)執(zhí)行目標(biāo)方法
        Object obj = methodInvocation.proceed();
        System.out.println("d_spring_auto_方法之后");
        return obj;

    }

}

測(cè)試

public class TestSpring {
    @Test
    public void testSpring() {
        String path = "cn/leyue/a_aop/d_spring_auto/beans.xml";
        ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
        UserService userService = application.getBean("userServiceId", UserService.class);
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
        System.out.println("------------------");
        ProxyTest proxy = application.getBean("proxyId", ProxyTest.class);
        proxy.sayHello();
    }

}

AspectJ

AspectJ介紹

  • AspectJ是一個(gè)基于Java 語(yǔ)言的AOP框架昧互。
  • Spring2.0以后新增了對(duì)AspectJ切點(diǎn)表達(dá)式支持。
  • @AspectJ 是AspectJ1.5新增功能伟桅,通過(guò)JDK5注解技術(shù)敞掘,允許直接在Bean類(lèi)中定義切面,新版本Spring框架楣铁,建議使用AspectJ方式來(lái)開(kāi)發(fā)AOP
  • 主要用途:自定義開(kāi)發(fā)

切入點(diǎn)表達(dá)式

1玖雁,execution 用于描述方法

語(yǔ)法:execution(修飾符 返回值 包.類(lèi).方法名(參數(shù)) throws 異常)
修飾符,一般省略
public 公共方法
*       任意
返回值 盖腕,不能省略
void    返回沒(méi)有值
String 返回值字符串
*       任意
cn.leyue.a_aop  固定包
cn.leyue.a_aop.*.service    a_aop包下面子包任意 (例如:cn.leyue.a_aop.staff.service)
cn.leyue.a_aop..            a_aop包下面的所有子包(含自己)
cn.leyue.a_aop.*.service..   a_aop包下面任意子包赫冬,固定目錄service ,service所有的子包
類(lèi)
UserServiceImpl      指定類(lèi)
*Impl               以Impl結(jié)尾
User*               以User開(kāi)頭
*                   任意
方法名,不能省略
addUser             固定方法
add*                以add開(kāi)頭
*Do                 以Do結(jié)尾
*                   任意
(參數(shù))
()              無(wú)參
(int)               一個(gè)整型參數(shù)
(int,int)       兩個(gè)
(..)                參數(shù)任意
throws 可省略溃列,一般不寫(xiě)
示例
execution(* com.itheima.crm.*.service..*.*(..))
<aop:pointcut expression="execution(* com.itheima.*WithCommit.*(..)) || 
                      execution(* com.itheima.*Service.*(..))" id="myPointCut"/>
2劲厌,within:匹配包或子包中的方法。
within(com.itheima.aop..*)
3听隐,this:匹配實(shí)現(xiàn)接口的代理對(duì)象中的方法补鼻。
this(com.itheima.aop.user.UserDAO)
4,target:匹配實(shí)現(xiàn)接口的目標(biāo)對(duì)象中的方法
target(com.itheima.aop.user.UserDAO)    
5雅任,args:匹配參數(shù)格式符合標(biāo)準(zhǔn)的方法
args(int,int)
6风范,bean(id) 對(duì)指定的bean所有的方法
bean('userServiceId')

AspectJ 通知類(lèi)型

  • aop聯(lián)盟定義通知類(lèi)型,具有特性接口椿访,必須實(shí)現(xiàn)乌企,從而確定方法名稱(chēng)虑润。
  • aspectj 通知類(lèi)型成玫,只定義類(lèi)型名稱(chēng)。已經(jīng)方法格式拳喻。

類(lèi)型

before:前置通知(應(yīng)用:各種校驗(yàn))
在方法執(zhí)行前執(zhí)行哭当,如果通知拋出異常,阻止方法運(yùn)行冗澈。
afterReturning:后置通知(應(yīng)用:常規(guī)數(shù)據(jù)處理)
方法正常返回后執(zhí)行钦勘,如果方法中拋出異常,通知無(wú)法執(zhí)行亚亲。
必須在方法執(zhí)行后才執(zhí)行彻采,所以可以獲得方法的返回值腐缤。
around:環(huán)繞通知(應(yīng)用:十分強(qiáng)大,可以做任何事情)
方法執(zhí)行前后分別執(zhí)行肛响,可以阻止方法的執(zhí)行岭粤。
必須手動(dòng)執(zhí)行目標(biāo)方法。
afterThrowing:拋出異常通知(應(yīng)用:包裝異常信息)
方法拋出異常后執(zhí)行特笋,如果方法沒(méi)有拋出異常剃浇,無(wú)法執(zhí)行。
after:最終通知(應(yīng)用:清理現(xiàn)場(chǎng))
方法執(zhí)行完畢后執(zhí)行猎物,無(wú)論方法中是否出現(xiàn)異常   
aspectJ.png

AspectJ 需要導(dǎo)入jar包

aop 聯(lián)盟規(guī)范  spring aop 實(shí)現(xiàn)         aspect規(guī)范    spring aspect 實(shí)現(xiàn)
Aspectjar.png

aspect 基于xml

  • 目標(biāo)類(lèi): 接口 + 實(shí)現(xiàn)
  • 切面類(lèi): 編寫(xiě)多個(gè)通知虎囚,采用aspectj 通知名稱(chēng)任意(方法名任意)
  • aop編程,將通知應(yīng)用到目標(biāo)類(lèi)
切面類(lèi)
/**
 * 切面類(lèi),含有多個(gè)通知
 */
public class MyAspect {
    public void myBefore(JoinPoint joinPoint) {
        System.out.println("前置通知: " + joinPoint.getSignature().getName());
        System.out.println("參數(shù): "+ Arrays.asList(joinPoint.getArgs()));

    }

    public void myAfterReturning(JoinPoint joinPoint, Object ret) {
        System.out.println("后置通知: " + joinPoint.getSignature().getName() + ",----->" + ret);
    }

    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("環(huán)繞通知: 前");
        Object obj = joinPoint.proceed();
        System.out.println("環(huán)繞通知: 后");
        return obj;
    }

    public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {
        System.out.println("拋出異常通知: "+e.getMessage());
    }

    public void myAfter(JoinPoint joinPoint) {
        System.out.println("最終通知");

    }
}
spring 配置
<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
       ">
       <!-- 1 創(chuàng)建目標(biāo)類(lèi) -->
        <bean id="userServiceId" class="cn.leyue.a_aop.e_aspect.a_xml.UserServiceImpl"></bean>
   
    <!-- 2 創(chuàng)建切面類(lèi)(通知) -->
    <bean id="myAspectId" class="cn.leyue.a_aop.e_aspect.a_xml.MyAspect"></bean>
        <!-- 3 aop編程 
        <aop:aspect> 將切面類(lèi) 聲明“切面”蔫磨,從而獲得通知(方法)
            ref 切面類(lèi)引用
        <aop:pointcut> 聲明一個(gè)切入點(diǎn)淘讥,所有的通知都可以使用。
            expression 切入點(diǎn)表達(dá)式
            id 名稱(chēng)质帅,用于其它通知引用
     -->

    <aop:config>
        <aop:aspect ref="myAspectId">

            <aop:pointcut id="myPointCut" expression="execution(* cn.leyue.a_aop.e_aspect.a_xml.UserServiceImpl.*(..))"></aop:pointcut>

            <!--前置通知-->
            <aop:before method="" pointcut="" pointcut-ref=""/>
                method : 通知适揉,及方法名
                pointcut :切入點(diǎn)表達(dá)式,此表達(dá)式只能當(dāng)前通知使用煤惩。
                pointcut-ref : 切入點(diǎn)引用嫉嘀,可以與其他通知共享切入點(diǎn)。
            通知方法格式:public void myBefore(JoinPoint joinPoint){
                參數(shù)1:org.aspectj.lang.JoinPoint  用于描述連接點(diǎn)(目標(biāo)方法)魄揉,獲得目標(biāo)方法名等


            <aop:before method="myBefore" pointcut-ref="myPointCut"></aop:before>
            <!--后置通知-->
            3.2后置通知  ,目標(biāo)方法后執(zhí)行剪侮,獲得返回值
            <aop:after-returning method="" pointcut-ref="" returning=""/>
                returning 通知方法第二個(gè)參數(shù)的名稱(chēng)
            通知方法格式:public void myAfterReturning(JoinPoint joinPoint,Object ret){
                參數(shù)1:連接點(diǎn)描述
                參數(shù)2:類(lèi)型Object,參數(shù)名 returning="ret" 配置的

            <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret"></aop:after-returning>
            3.3 環(huán)繞通知 
            <aop:around method="" pointcut-ref=""/>
            通知方法格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
                返回值類(lèi)型:Object
                方法名:任意
                參數(shù):org.aspectj.lang.ProceedingJoinPoint
                拋出異常
            執(zhí)行目標(biāo)方法:Object obj = joinPoint.proceed();

            <aop:around method="myAround" pointcut-ref="myPointCut"></aop:around>

            <!--拋出異常-->
            <aop:after-throwing method="" pointcut-ref="" throwing=""/>
                throwing :通知方法的第二個(gè)參數(shù)名稱(chēng)
            通知方法格式:public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
                參數(shù)1:連接點(diǎn)描述對(duì)象
                參數(shù)2:獲得異常信息洛退,類(lèi)型Throwable 瓣俯,參數(shù)名由throwing="e" 配置


            <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"></aop:after-throwing>
            <!--最終通知-->
           <aop:after method="myAfter" pointcut-ref="myPointCut"></aop:after>
        </aop:aspect>
        
    </aop:config>


</beans>

aspect 基于注解

spring 配置
<?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
       ">
    <!--掃描 注解類(lèi)-->
    <context:component-scan base-package="cn.leyue.a_aop.e_aspect.b_anno"></context:component-scan>
    <!--確定 aop注解生效-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
替換AOP
  • 必須進(jìn)行aspectj自動(dòng)代理

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    <context:component-scan base-package="cn.leyue.a_aop.e_aspect.b_anno"></context:component-scan>
切面類(lèi)
/**
 * 切面類(lèi),含有多個(gè)通知
 */
@Component
@Aspect
public class MyAspect {

    //聲明公共變量
    @Pointcut("execution(* cn.leyue.a_aop.e_aspect.b_anno.UserServiceImpl.*(..))")
    private void myPointCut() {

    }



    //切入點(diǎn)當(dāng)前有效
//    @Before("execution(* cn.leyue.a_aop.e_aspect.b_anno.UserServiceImpl.*(..))")
    public void myBefore(JoinPoint joinPoint) {
        System.out.println("前置通知: " + joinPoint.getSignature().getName());
        System.out.println("參數(shù): "+ Arrays.asList(joinPoint.getArgs()));

    }

//    @AfterReturning(value = "myPointCut()",returning = "ret")
    public void myAfterReturning(JoinPoint joinPoint, Object ret) {
        System.out.println("后置通知: " + joinPoint.getSignature().getName() + ",----->" + ret);
    }

//    @Around(value = "myPointCut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("環(huán)繞通知: 前");
        Object obj = joinPoint.proceed();
        System.out.println("環(huán)繞通知: 后");
        return obj;
    }

    @AfterThrowing(value = "myPointCut()",throwing = "e")
    public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {
        System.out.println("拋出異常通知: "+e.getMessage());
    }

//    @After(value="myPointCut()")
    public void myAfter(JoinPoint joinPoint) {
        System.out.println("最終通知");

    }
}

public interface UserService {
    void addUser(String username);
    String updateUser();
    void deleteUser();
}


@Service("userServiceId")
public class UserServiceImpl implements UserService {

    @Override
    public void addUser(String username) {
        System.out.println("b_anno------addUser  "+username);
    }

    @Override
    public String updateUser() {
        System.out.println("b_anno------updateUser");
        int i= 1/0;
        return "back";
    }

    @Override
    public void deleteUser() {
        System.out.println("b_anno------deleteUser");

    }
}
測(cè)試注解
public class TestAspectAnno {

    @Test
    public void testanno() {
        String path ="cn/leyue/a_aop/e_aspect/b_anno/beans.xml";
        ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
        UserService userService = application.getBean("userServiceId",UserService.class);
        userService.addUser("anno");
        userService.updateUser();
        userService.deleteUser();
    }
}

JdbcTemplate

  • spring 提供用于操作JDBC工具類(lèi),類(lèi)似DBUtils
  • 依賴(lài)連接池DataSource(數(shù)據(jù)源)

環(huán)境搭建

導(dǎo)入jar包

jdbc1.png
javabean
public class Building {
    private String buname;
    private int id;
    private String buaddress;
    private double aveprice;

    public String getBuname() {
        return buname;
    }

    public void setBuname(String buname) {
        this.buname = buname;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getBuaddress() {
        return buaddress;
    }

    public void setBuaddress(String buaddress) {
        this.buaddress = buaddress;
    }

    public double getAveprice() {
        return aveprice;
    }

    public void setAveprice(double aveprice) {
        this.aveprice = aveprice;
    }

    @Override
    public String toString() {
        return "Building{" +
                "buname='" + buname + '\'' +
                ", id=" + id +
                ", buaddress='" + buaddress + '\'' +
                ", aveprice=" + aveprice +
                '}';
    }
}
使用api
@Test
public void jdbc() {
    //1 創(chuàng)建數(shù)據(jù)源(連接池)dbcp
    BasicDataSource dataSource = new BasicDataSource();

    //基本四項(xiàng)
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8");
    dataSource.setUsername("root");
    dataSource.setPassword("");

    //創(chuàng)建模板
    JdbcTemplate jdbcTemplate  = new JdbcTemplate();
    jdbcTemplate.setDataSource(dataSource);

    //通過(guò)api操作
    String sql = "select * from fc_building limit ?";
    List<Building> datas = jdbcTemplate.query(sql, new Object[]{10}, ParameterizedBeanPropertyRowMapper.newInstance(Building.class));
    for (Building building : datas) {
        System.out.println(building);
    }

}
DAO
public class BuildingDao {
    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public List<Building> findAll() {
        List<Building> datas = jdbcTemplate.query("select * from fc_building limit ?",new Object[]{10},
                ParameterizedBeanPropertyRowMapper.newInstance(Building.class));
        return datas;
    }

}

配置DBCP

<?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">

    <bean id="dataSourceId" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8"></property>
        <property name="username" value="root"></property>
        <property name="password" value=""></property>
    </bean>

    <bean id="jdbcTemplateId" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSourceId"></property>
    </bean>

    <bean id="buildingDaoId" class="cn.leyue.jdbc.dbcp.BuildingDao">
        <property name="jdbcTemplate" ref="jdbcTemplateId"></property>
    </bean>

</beans>

配置的C3P0

<?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">

    <bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
       <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8"></property>
        <property name="user" value="root"></property>
        <property name="password" value=""></property>
    </bean>

  <bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
      <property name="dataSource" ref="dataSourceId"></property>
  </bean>

    <bean id="buildingDaoId" class="cn.leyue.jdbc.dbcp.BuildingDao">
        <property name="jdbcTemplate" ref="template"></property>
    </bean>
    
</beans>

使用JdbcDaoSupport

dao 需要繼承 JdbcDaoSupport
public class BuildingSupportDao extends JdbcDaoSupport {
    public List<Building> findAll() {
        List<Building> datas = getJdbcTemplate().query("select * from fc_building limit ?",new Object[]{10},
                ParameterizedBeanPropertyRowMapper.newInstance(Building.class));
        return datas;
    }
}
spring 配置文件
<?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">

    <bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
       <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8"></property>
        <property name="user" value="root"></property>
        <property name="password" value=""></property>
    </bean>

   <!--
        dao 繼承 JdbcDaoSupport兵怯,之后只需要注入數(shù)據(jù)源彩匕,底層將自動(dòng)創(chuàng)建模板
   -->
    <bean id="buildingDaoId" class="cn.leyue.jdbc.support.BuildingSupportDao">
       <property name="dataSource" ref="dataSourceId"></property>
    </bean>

</beans>

配置properties

properties 文件
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8
jdbc.user=root
jdbc.password=
spring配置
<?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: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/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <!--
        加載配置文件
        "classpath" 前綴表示src下
        在配置文件之后通過(guò)${key}獲得內(nèi)容
    -->
    <context:property-placeholder location="classpath:cn/leyue/jdbc/properties/jdbcInfo.properties"/>

    <!--創(chuàng)建數(shù)據(jù)源c3p0-->
    <bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="user" value="${jdbc.user}"></property>
    </bean>

    <bean id="daoId" class="cn.leyue.jdbc.support.BuildingSupportDao">
        <property name="dataSource" ref="dataSourceId"></property>
    </bean>

</beans>

測(cè)試類(lèi)

@Test
public void c3p0() {
    String path = "cn/leyue/jdbc/c3p0/beans.xml";
    ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
    BuildingDao dao = application.getBean("buildingDaoId", BuildingDao.class);
    System.out.println("    ===c3p0===    ");
    List<Building> datas = dao.findAll();
    for (Building building : datas) {
        System.out.println(building);
    }
}

 @Test
public void support() {
    String path = "cn/leyue/jdbc/support/beans.xml";
    ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
    BuildingSupportDao dao = application.getBean("buildingDaoId", BuildingSupportDao.class);
    System.out.println("    ===support===    ");
    List<Building> datas = dao.findAll();
    for (Building building : datas) {
        System.out.println(building);
    }
}

 @Test
public void propertis() {
    String path = "cn/leyue/jdbc/properties/beans.xml";
    ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
    BuildingSupportDao dao = application.getBean("daoId", BuildingSupportDao.class);
    System.out.println("    ===propertis===    ");
    List<Building> datas = dao.findAll();
    for (Building building : datas) {
        System.out.println(building);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市媒区,隨后出現(xiàn)的幾起案子驼仪,更是在濱河造成了極大的恐慌,老刑警劉巖袜漩,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绪爸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡宙攻,警方通過(guò)查閱死者的電腦和手機(jī)奠货,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)座掘,“玉大人递惋,你說(shuō)我怎么就攤上這事柔滔。” “怎么了萍虽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵廊遍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我贩挣,道長(zhǎng)喉前,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任王财,我火速辦了婚禮卵迂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绒净。我一直安慰自己见咒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布挂疆。 她就那樣靜靜地躺著改览,像睡著了一般。 火紅的嫁衣襯著肌膚如雪缤言。 梳的紋絲不亂的頭發(fā)上宝当,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音胆萧,去河邊找鬼庆揩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛跌穗,可吹牛的內(nèi)容都是我干的订晌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蚌吸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锈拨!你這毒婦竟也來(lái)了购城?” 一聲冷哼從身側(cè)響起瓮床,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎城豁,沒(méi)想到半個(gè)月后肉迫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體验辞,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡稿黄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年喊衫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杆怕。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡族购,死狀恐怖壳贪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寝杖,我是刑警寧澤违施,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站瑟幕,受9級(jí)特大地震影響磕蒲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜只盹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一辣往、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧殖卑,春花似錦站削、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至菩鲜,卻和暖如春园细,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背接校。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工珊肃, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人馅笙。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓伦乔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親董习。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烈和,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容