Spring 动态代理&AOP&事务入门

159 阅读2分钟

1.新建Maven项目,导入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>org.example</groupId>
    <artifactId>spring-aop</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
    </dependencies>

</project>

2.新建需要进行动态代理的接口以及实现类和增强方法

package com.abchina.aop;

public interface TargetInterface {
    public void method();
}

package com.abchina.aop;

public class Target implements TargetInterface {
    public void method() {
        System.out.println("Target Running....");
    }
}

2.1新建测试类使用JDK自带的动态代理

package com.abchina.test;

import com.abchina.aop.TargetInterface;
import com.abchina.aop.Target;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;


public class AopTest {
    //基于JDK的动态代理
    @Test
    public void testAop() {

        final Target target = new Target();
        TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("前置增强代码...");
                        Object invoke = method.invoke(target, args);
                        System.out.println("后置增强代码...");
                        return invoke;
                    }
                });
        proxy.method();
    }
}

2.2使用cglib动态代理

package com.abchina.test;

import com.abchina.aop.TargetInterface;
import com.abchina.aop.Target;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

public class AopTest {

    //基于cglib的动态代理
    @Test
    public void testCglibAop() {
        final Target target = new Target();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Target.class);
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("前置增强代码...");
                Object invoke = method.invoke(target, objects);
                System.out.println("后置增强代码...");
                return invoke;
            }
        });
        Target proxy = (Target) enhancer.create();
        proxy.method();
    }

    @Resource
    private TargetInterface target;
    @Test
    public void xmlAopTest() {
        target.method();
    }
}

3.使用xml方式配置AOP

3.1新建切面类

package com.abchina.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;


public class MyAspect {
    public void before() {
        System.out.println("前置代码增强....");
    }
}

3.2编写xml配置文件

3.2.1 配置目标类和切面类

<!--    配置目标类-->
    <bean id="target" class="com.abchina.aop.Target"/>
<!--    配置切面类-->
    <bean id="myAspect" class="com.abchina.aop.MyAspect"/>

3.2.2 织入切面

    <aop:config>
        <aop:aspect ref="myAspect">
            <aop:before method="before" pointcut="execution(public void com.abchina.aop.Target.method())"/>
        </aop:aspect>
    </aop:config>

3.2.3新建测试类测试AOP

package com.abchina.test;

import com.abchina.aop.TargetInterface;
import com.abchina.aop.Target;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {

    @Resource
    private TargetInterface target;
    @Test
    public void xmlAopTest() {
        target.method();
    }
}

4.使用注解方式配置AOP

4.1开启注解组件扫描和aop的自动代理

<!--    注解开发需要对组件所在的包进行扫描-->
    <context:component-scan base-package="com.abchina.aop"/>
<!--    aop的自动代理-->
    <aop:aspectj-autoproxy/>

4.2 将目标类注册到spring容器中

@Component("target")
public class Target implements TargetInterface 

4.3 将自定义的切面注册到spring容器中并配置切面

notice:切面可以注册在类上以及方法上,切面表达式可以简写

package com.abchina.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component("myAspect")
@Aspect
public class MyAspect {
    @Before("execution(* com.abchina.aop.*.*(..))")
    public void before() {
        System.out.println("前置代码增强....");
    }
}

5.源码链接