1. 程式人生 > >spring 非xml配置 非@Aspect 註解 使用aop切面程式設計 方便深入學習aop原始碼

spring 非xml配置 非@Aspect 註解 使用aop切面程式設計 方便深入學習aop原始碼

使用maven專案,實現基於純java的類程式碼實現spring的aop功能,不用xml配置,不用aop註解實現aop,直接使用類的java程式碼實現,直接執行main方法,看到aop結果輸出

//pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.dddd</groupId>
    <artifactId>spring</artifactId>
    <version>1.0</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <spring.version>4.3.3.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.10</version>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
//logback.xml   配置日誌,顯示所有spring內部日誌,通過日誌,檢視執行流程
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="false" scanPeriod="30 second">

    <property name="MAXHISTORY" value="100"/>
    <timestamp key="DATETIME" datePattern="yyyy-MM-dd HH:mm:ss"/>

    <!-- 控制檯列印 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder charset="utf-8">
            <pattern>[%-5level] %d{${DATETIME}} [%thread] %logger{36} - %m%n
            </pattern>
        </encoder>
    </appender>


    <root level="ALL">      
        <appender-ref ref="STDOUT"/>    
    </root>
</configuration>
//ServInter.java   介面類
package com.dddd.aop;

public interface ServInter {
    public void say();
}
//MyService.java   介面實現類,被代理物件
package com.dddd.aop;

import org.springframework.stereotype.Service;

@Service
public class MyService implements ServInter {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void say() {

        System.out.println("MyService say:" + name);
    }
}
//MyBeforeAop.java   aop前置通知處理類
package com.dddd.aop;

import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class MyBeforeAop implements MethodBeforeAdvice {

    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("before aop ["+method.getName()+"] do sth...................");
    }
}

上面三個類檔案是準備工作,下面寫一個main方法,實現spring的aop,上面的註解是為了,方便快速新增bean到spring中

//Test.java

public class Test {

    public static void main(String[] args) {
    
        //aop  使用ProxyFactoryBean
        //AnnotationConfigApplicationContext可以換成ApplicationContext 介面
        //使用支援註解的容器,掃描包,直接新增bean
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("com.dddd.aop");
        ServInter servInter = ac.getBean(ServInter.class);
        MyBeforeAop myAop = (MyBeforeAop) ac.getBean("myBeforeAop");

        //代理物件,aop的關鍵類就是這個代理類,會自動識別,如果是介面代理,使用jdk的代理,其他使用cglib代理
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setBeanFactory(ac.getBeanFactory());
        proxyFactoryBean.setInterceptorNames("myBeforeAop");
        proxyFactoryBean.setInterfaces(ServInter.class);
        proxyFactoryBean.setTarget(servInter);

        //這裡注意下面物件獲取,不能直接使用上面的從getBean獲取的,要不然沒有aop效果
        //aop的本質就是使用一個代理類(理解為包裹了原來的bean的一個代理bean)
        //呼叫的代理類產生的你需要的bean的方法,代理類才能知道你要呼叫的是哪個類的哪個方法,以實現代理
        //直接呼叫bean的方法,代理類是無法知道的,所有就aop不了了
        ServInter servInterProxy = (ServInter) proxyFactoryBean.getObject();
        servInterProxy.say();


       //aop2  使用ProxyFactory
       ac = new AnnotationConfigApplicationContext("com.dddd.aop");
        servInter = ac.getBean(ServInter.class);
        myAop = (MyBeforeAop) ac.getBean("myBeforeAop");

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(servInter);
        proxyFactory.addAdvice(myAop);

        servInterProxy = (ServInter) proxyFactory.getProxy();
        servInterProxy.say();
    }
}

其他幾種aop方式類似, 列出介面名

org.springframework.aop.MethodBeforeAdvice   前置
org.springframework.aop.AfterReturningAdvice   後置
org.springframework.aop.ThrowsAdvice       異常攔截
org.aopalliance.intercept.MethodInterceptor   環繞