/*
* spring的AOP面向切面編程
* 理解:在不改變原來方法的基礎上,實現方法增強處理
* 實現方式:
* 1.jdk的Proxy:動態代理,執行的時候處理,要求必須有接口、實現類,代理創建的是實現類的子類。
* 2.cglib:第三方實現的動態代理,要求必須有父類,代理創建的是父類的子類,比jdk實現的要靈活。
* AOP中如果有接口則用jkd動態代理,沒有則用cglib
*
* */
jdk實現代碼:
代碼結構:
1.目標類:Target
2.目標接口類:TargetInterface
3.增強方法類:Advice
4.用Proxy.newProxyInstance實現對目標類的方法增強
public class Target implements TargetInterface { @Override public void save() { System.out.println("save run ..."); } }
public interface TargetInterface { void save(); }
public class Advice { public void before(){ System.out.println("增強前方法。。。。"); } public void after(){ System.out.println("增強后方法"); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyText { public static void main(String[] args) { Target target=new Target(); Advice advice=new Advice(); TargetInterface proxyInstance = (TargetInterface)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { advice.after(); Object invoke = method.invoke(target, args); advice.after(); return invoke; } }); proxyInstance.save(); } }
cglib實現:
目標類和增強方法一樣
import org.springframework.cglib.proxy.*; import java.lang.reflect.Method; /* * spring的AOP面向切面編程 * 理解:在不改變原來方法的基礎上,實現方法增強處理 * 實現方式: * 1.jdk的Proxy:動態代理,執行的時候處理,要求必須有接口、實現類,代理創建的是實現類的子類。 * 2.cglib:第三方實現的動態代理,要求必須有父類,代理創建的是父類的子類,比jdk實現的要靈活。 * AOP中如果有接口則用jkd動態代理,沒有則用cglib * * cglib步驟: * 1.導入包org.aspectj * 2.代碼實現,如下。實現代碼和Proxy.newProxyInstance差不多 * */ public class ProxyTest { public static void main(String[] args) { //目標對象 Target target=new Target(); //增強對象 Advice advice=new Advice(); //1.創建增強器 Enhancer enhancer=new Enhancer(); //2.設置父目標 enhancer.setSuperclass(Target.class); //3.設置回調 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { advice.before(); Object invoke = method.invoke(target, objects); advice.after(); return invoke; } }); //4.創建代理對象 Target proxy = (Target) enhancer.create(); proxy.save(); } }
spring配置方式實現;
包配置:
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
xml方式實現:
1.target類
public class Target implements TargetInterface { @Override public void save() { System.out.println("save run ..."); } }
2.接口
public interface TargetInterface { void save(); }
3.切面類
import org.aspectj.lang.ProceedingJoinPoint; /* * aop的重點概念: Pointcut(切入點):被增強的方法 Advice(通知/ 增強):封裝增強業務邏輯的方法 Aspect(切面):切點+通知 Weaving(織入):將切點與通知結合的過程 * * * * 前置通知 <aop:before> 用於配置前置通知。指定增強的方法在切入點方法之前執行 后置通知 <aop:after-returning> 用於配置后置通知。指定增強的方法在切入點方法之后執行 環繞通知 <aop:around> 用於配置環繞通知。指定增強的方法在切入點方法之前和之后都執行 異常拋出通知 <aop:throwing> 用於配置異常拋出通知。指定增強的方法在出現異常時執行 最終通知 <aop:after> 用於配置最終通知。無論增強方式執行是否有異常都會執行 * */ public class MyAspect { public void before(){ System.out.println("before增強方法"); } public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around增強前"); Object proceed = pjp.proceed(); System.out.println("around增強后"); return proceed; } }
4.配置
<?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="target" class="cn.web.aop.Target"></bean> <!--切面對象--> <bean id="myAspect" class="cn.web.aop.MyAspect"></bean> <!--配置織入:告訴spring哪些方法需要那總增強--> <aop:config> <!--聲明切面--> <aop:aspect ref="myAspect"> <!--切點表達式--> <aop:pointcut id="pointcut" expression="execution( * cn.web.aop.Target.*())"></aop:pointcut> <!--切面:切點+通知--> <!--<aop:before method="before" pointcut="execution(public void cn.web.aop.Target.save())"></aop:before>--> <!--返回值、包、類、方法都可以用通配符取代,表示里面的所有類、方法等--> <aop:before method="before" pointcut="execution( * cn.web.aop.Target.*())"></aop:before> <aop:around method="around" pointcut-ref="pointcut"></aop:around> </aop:aspect> </aop:config> </beans>
5.測試
import cn.web.aop.TargetInterface; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AopTest { @Autowired private TargetInterface target; @Test public void test(){ target.save(); } }
注解方式實現;
就列些不同的
1.切面類
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /* * aop的重點概念: Pointcut(切入點):被增強的方法 Advice(通知/ 增強):封裝增強業務邏輯的方法 Aspect(切面):切點+通知 Weaving(織入):將切點與通知結合的過程 * * * * 前置通知 <aop:before> 用於配置前置通知。指定增強的方法在切入點方法之前執行 后置通知 <aop:after-returning> 用於配置后置通知。指定增強的方法在切入點方法之后執行 環繞通知 <aop:around> 用於配置環繞通知。指定增強的方法在切入點方法之前和之后都執行 異常拋出通知 <aop:throwing> 用於配置異常拋出通知。指定增強的方法在出現異常時執行 最終通知 <aop:after> 用於配置最終通知。無論增強方式執行是否有異常都會執行 * */ @Component @Aspect public class MyAspect { @Before("execution(* cn.web.aop.Target.*(..))") public void before(){ System.out.println("before增強方法"); } @Around("pointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around增強前"); Object proceed = pjp.proceed(); System.out.println("around增強后"); return proceed; } @AfterReturning("pointcut()") public void afterReturning(){ System.out.println("afterReturning返回后"); } //設置切點表達式:可以共用 @Pointcut("execution(* cn.web.aop.Target.*(..))") public void pointcut(){ } }
2.配置
<?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.itheima.anno"/> <!--aop自動代理--> <aop:aspectj-autoproxy/> </beans>
3.測試
import cn.web.anno.TargetInterface; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext_anno.xml") public class AnnoTest { @Autowired private TargetInterface target; @Test public void test(){ target.save(); } }