Spring系列(三)AOP详解

一.Spring—AOP概述

AOP:面向切面编程
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

二.AOP

直接上代码,具体解释见代码注释
Spring系列(三)AOP详解_第1张图片
AOP.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/cjx/aop/aop.xml")
public class AOP {//AOP测试
    //Interface接口相当于UserService
    //Target类相当于UserServiceImpl
    @Resource(name="target")
    private Interface us;

    @Test
    public void fun(){
        us.delete();//此方法无异常
        System.out.println("——分割线——");
        us.save();//此方法内置了一个异常,用于演示
    }

    /*AOP:面向切面编程思想
     * 思想总结:横向重复的代码,用纵向AOP抽取出来。
     */

    /*动态代理可以体现AOP思想
     * 动态代理:对目标对象的方法进行增强
     * Cglib代理可以体现AOP思想
     * Cglib代理:对目标对象的方法进行增强
     */

    /*spring的AOP开发
     * spring封装了动态代理(基于接口)的代码和Cglib代理(基于继承)的代码
     * 使用 spring就不用手写动态代理的代码和Cglib代理的代码
     * 因此使用 spring就可以对任何类进行增强
     * 例如:/spring/src/cjx/aopCglib/AopCglib.java
     * 例如:/spring/src/cjx/aopProxy/AopProxy.java
     */

    /*spring的AOP名词解释
     * Joinpoint(连接点):目标对象中,所有可以增强的方法
     * Pointcut(切入点):目标对象中,所有已经增强(想要增强)的方法
     * Advice(通知/增强):增强目标对象的代码
     * Target(目标对象):被代理的对象
     * Weaving(织入):将通知应用到切入点的过程
     * Proxy(代理):将通知织入到目标对象之后,形成代理对象
     * Aspect(切面):切入点+通知
     */
}

aop.xml


<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
    
    
    
    
    <bean name="target" class="cjx.aop.Target">bean>
    
    <bean name="advice" class="cjx.aop.Advice">bean>
    
    <aop:config>
        
    <aop:pointcut expression="execution(* cjx.aop.Target.*(..))"  id="pc" />
    <aop:aspect ref="advice">
        
        <aop:before method="before" pointcut-ref="pc" />
        
        <aop:after-returning method="afterReturning" pointcut-ref="pc" />
        
        <aop:around method="around" pointcut-ref="pc" />
        
        <aop:after-throwing method="afterException" pointcut-ref="pc" />
        
        <aop:after method="after" pointcut-ref="pc" />

    aop:aspect>
    aop:config>
beans>

Interface.java

public interface Interface {
    void save();
    void delete();
    void update();
    void find();
}

Advice.java

public class Advice {//通知类
    //Advice(通知/增强):增强目标对象的代码
    //定义通知时,方法名随意
    //前置通知:目标方法运行之前调用
    public void before(){
        System.out.println("前置通知");
    }
    //后置通知:目标方法运行之后调用,如果出现异常不会调用
    public void afterReturning(){
        System.out.println("后置通知,出现异常不会调用");
    }
    //环绕通知:目标方法运行之前和运行之后都调用
    //环绕通知必须接受一个ProceedingJoinPoint 对象
    //环绕通知必须手动调用目标方法,并返回目标方法
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕通知之前部分");
        Object proceed = pjp.proceed();//调用目标方法
        System.out.println("环绕通知之后部分");
        return proceed;
    }
    //异常拦截通知:如果出现异常,就会调用
    public void afterException(){
        System.out.println("出现异常了");
    }
    //后置通知:目标方法运行之后调用,无论是否出现异常都会调用
    public void after(){
        System.out.println("后置通知,无论是否出现异常都会调用");
    }
}

Target.java

public class Target implements Interface{//目标对象类
    //Target(目标对象):被代理的对象
    @Override
    public void save() {
        System.out.println("save");     
        //用于演示异常
        int i=1/0;
        System.out.println(i);
    }
    @Override
    public void delete() {
        System.out.println("delete");       
    }
    @Override
    public void update() {
        System.out.println("update");       
    }
    @Override
    public void find() {
        System.out.println("find");     
    }
}

三.AOP注解

直接上代码,具体解释见代码注释
这里写图片描述
AdviceAnnotate.java


@Aspect//表示该类是通知类
public class AdviceAnnotate {//通知注解类    
    //抽取表达式的方法
    @Pointcut("execution(* cjx.aop.Target.*(..))")
    public void pc(){}  
    //指定该方法是前置通知,并指定切入点
    @Before("AdviceAnnotate.pc()")
    public void before(){
        System.out.println("前置通知AOPAnnotate");
    }   
    //指定该方法是后置通知,并指定切入点
    @AfterReturning("AdviceAnnotate.pc()")
    public void afterReturning(){
        System.out.println("后置通知,出现异常不会调用AOPAnnotate");
    }   
    //指定该方法是环绕通知,并指定切入点
    @Around("AdviceAnnotate.pc()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕通知之前部分AOPAnnotate");
        Object proceed = pjp.proceed();//调用目标方法
        System.out.println("环绕通知之后部分AOPAnnotate");
        return proceed;
    }   
    //指定该方法是异常拦截通知,并指定切入点
    @AfterThrowing("execution(* cjx.aop.Target.*(..))")
    public void afterException(){
        System.out.println("出现异常了AOPAnnotate");
    }   
    //指定该方法是后置通知,并指定切入点
    @After("execution(* cjx.aop.Target.*(..))")
    public void after(){
        System.out.println("后置通知,无论是否出现异常都会调用AOPAnnotate");
    }
    //对比不使用注解的方式,发现输出顺序有区别,原因未知 
}

aopAnnotate.xml


<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">

    
    
    <bean name="target" class="cjx.aop.Target">bean>
    
    <bean name="advice" class="cjx.aopAnnotate.AdviceAnnotate">bean>
    
    <aop:aspectj-autoproxy>aop:aspectj-autoproxy>
beans>

AOPAnnotate.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:cjx/aopAnnotate/aopAnnotate.xml")
public class AOPAnnotate {
    @Resource(name="target")
    private Interface us;   
    @Test
    public void fun(){
        us.delete();//此方法无异常
        System.out.println("——分割线——");
        us.save();//此方法内置了一个异常,用于演示
    }
}

四.AOP原理

直接上代码,具体解释见代码注释

1.Cglib

Spring系列(三)AOP详解_第2张图片
AopCglib.java

//此包代码演示了spring的AopCglib代理部分原理,观光代码
public class AopCglib {//AopCglib代理,基于继承代理
//第三方代理技术,cglib代理.可以对任何类生成代理.代理的原理是对目标对象进行继承代理.
//如果目标对象被final修饰.那么该类无法被cglib代理.
    @Test
    public void fun(){
        UserServiceProxyFactory factory=new UserServiceProxyFactory();
        UserService usProxy=factory.getUserServiceProxy();
        usProxy.save();
        //判断代理对象是否属于被代理对象类型
        //代理对象继承了被代理对象,所以结果是true
        System.out.println(usProxy instanceof UserServiceImpl);
    }
    /*spring的AOP名词解释
     * Joinpoint(连接点):目标对象中,所有可以增强的方法
     * Pointcut(切入点):目标对象中,所有已经增强的方法
     * Advice(通知/增强):增强目标对象的代码
     * Target(目标对象):被代理的对象
     * Weaving(织入):将通知应用到切入点的过程
     * Proxy(代理):将通知织入到目标对象之后,形成代理对象
     * Aspect(切面):切入点+通知
     */
}

UserService.java

public interface UserService {
    void save();
    void delete();
    void update();
    void find();
}

UserServiceImpl.java

public class UserServiceImpl implements UserService{
    @Override
    public void save() {
        System.out.println("save");     
    }
    @Override
    public void delete() {
        System.out.println("delete");

    }
    @Override
    public void update() {
        System.out.println("update");       
    }
    @Override
    public void find() {
        System.out.println("find");     
    }
}

UserServiceProxyFactory.java

public class UserServiceProxyFactory implements MethodInterceptor{  
    public UserService getUserServiceProxy(){
        //生成代理对象
        Enhancer en=new Enhancer();
        //设置对谁进行代理
        en.setSuperclass(UserServiceImpl.class);
        //设置代理要做什么
        en.setCallback(this);
        //创建代理对象
        UserService us = (UserService) en.create();
        return us;
    }
    @SuppressWarnings("unused")
    @Override
    public Object intercept(Object proxyObj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
        //打开事务
        System.out.println("AopCglib打开事务");
        //调用原有方法
        Object returnValue = methodProxy.invokeSuper(proxyObj, arg);
        //提交事务
        System.out.println("AopCglib提交事务");
        return null;
    }
}

2.Proxy

Spring系列(三)AOP详解_第3张图片
AopProxy.java

//此包代码演示了spring的AopProxy代理部分原理,观光代码
public class AopProxy {//AOP代理,类似于动态代理(了解)
    //被代理对象必须要实现接口,才能产生代理对象.如果没有接口将不能使用动态代理技术
    @Test
    public void fun(){
        UserService us=new UserServiceImpl();
        UserServiceProxyFactory factory =new UserServiceProxyFactory(us);
        UserService usProxy=factory.getUserServiceProxy();
        usProxy.save();
        //代理对象与被代理对象实现了相同的接口
        //代理对象与被代理对象没有继承关系
        System.out.println(usProxy instanceof UserServiceImpl);
    }
    /*spring的AOP名词解释
     * Joinpoint(连接点):目标对象中,所有可以增强的方法
     * Pointcut(切入点):目标对象中,所有已经增强的方法
     * Advice(通知/增强):增强目标对象的代码
     * Target(目标对象):被代理的对象
     * Weaving(织入):将通知应用到切入点的过程
     * Proxy(代理):将通知织入到目标对象之后,形成代理对象
     * Aspect(切面):切入点+通知
     */
}

UserService.java

public interface UserService {
    void save();
    void delete();
    void update();
    void find();
}

UserServiceImpl.java

public class UserServiceImpl implements UserService{
    @Override
    public void save() {
        System.out.println("save");     
    }
    @Override
    public void delete() {
        System.out.println("delete");       
    }
    @Override
    public void update() {
        System.out.println("update");       
    }
    @Override
    public void find() {
        System.out.println("find");     
    }

}

UserServiceProxyFactory.java

public class UserServiceProxyFactory implements InvocationHandler{
    private UserService us; 
    public UserServiceProxyFactory(UserService us) {
        super();
        this.us = us;
    }
    public UserService getUserServiceProxy(){
        //生成动态代理
        UserService usProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), this);
        //返回
        return usProxy;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("AopProxy打开事务!");
        Object invoke = method.invoke(us, args);
        System.out.println("AopProxy提交事务!");
        return invoke;
    }
}

你可能感兴趣的:(JAVA-WEB)