天天看点

spring框架学习二(aop面向切面编程)

一,什么事aop(本文以事务为例)

AOP技术利用一种称为“横切”的技术,解剖封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,这样就能减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。

二,首先,我们先做一个简单的静态代理

业务接口和实现

接口GoodService

public interface GoodService {
    public void save();
}
           

实现:GoodServiceImpl

public class GoodServiceImpl implements GoodService{
    @Override
    public void save() {
        System.out.println("保存操作");
    }
}
           

事务接口和实现

Trans

package com.study.demo2;
public interface Trans {
    public void begin();
    public void commit();
    public void roolback();
}
           

TransImpl

package com.study.demo2;
public class TransImpl implements Trans{
    @Override
    public void begin() {
        System.out.println("开启事务");
    }
    @Override
    public void commit() {
        System.out.println("提交事务");
    }
    @Override
    public void roolback() {
        System.out.println("回滚事务");
    }
}
           

现在我们要把事务加入业务中,如何去加,这是就用到了代理,代理的作用就是组装事务和业务

静态代理类:

package com.study.demo2;
public class StaticProxy {
    private GoodService goodService;
    private Trans trans;
    public StaticProxy() {
    }
    public StaticProxy(GoodService goodService, Trans trans) {
        this.goodService = goodService;
        this.trans = trans;
    }
//    执行组装
    public void proxyMethod(){
        trans.begin();
        try {
            goodService.save();
            trans.commit();
        } catch (Exception e) {
            trans.roolback();
            e.printStackTrace();
        }
    }
}
           

测试

public class RunTimeTest {
    public static void main(String[] args) {
        GoodService goodService=new GoodServiceImpl();
        Trans trans=new TransImpl();
        StaticProxy staticProxy=new StaticProxy(goodService,trans);
        staticProxy.proxyMethod();
    }
}
           

如上我们便完成了一个简单的静态代理,将业务和事务组装起来。但是却有一个问题:如果我们的业务service中有多个方法,如加一个add()方法,我们想要在这个方法上组装事务,应该如何做?

就需要去更改代理类中的proxyMethod()方法中的goodService.save(),相当不方便,那么怎么解决,这就用到了动态代理

三,jdk1.3后提供了一个java.lang.reflect.InvocationHandler代理接口,可以用来实现动态代理

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

上面的业务CoodService和事务Trans不变,我们直接看代理类(Myproxy实现InvocationHandler接口),用法:下面注释写的很清楚,用的是相当于反射的原理

package com.study.demo3;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * @author: Demon
 * @date: 2019/2/10
 * @time: 15:10
 * Description:
 */
public class MyProxy implements InvocationHandler{
    /**
     * 组装操作,
     * 业务(被代理对象)
     * 代理后增强的代码(增强代码)
    * */
    private Object object;//被代理对象,此时并不知道传入的业务对象是什么,以及有什么方法,所以用Object接收
    private Trans trans;//增强的事务操作
    public MyProxy() {
    }
    public MyProxy(Object object, Trans trans) {
        this.object = object;
        this.trans = trans;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        trans.begin();//事务开启
        try {
            object=method.invoke(object,args);//目标方法执行
            trans.commit();
        } catch (Exception e) {
            e.printStackTrace();
            trans.roolback();
        }
        return object;
    }
}
           

测试(jdk的这个代理和spring的代理不同,jdk的是针对接口的;spring是针对类的,用cglib实现的,不需要接口)

package com.study.demo3;
import java.lang.reflect.Proxy;
public class RunTest {
    public static void main(String[] args) {
        //动态代理类:(被代理类,代理类的接口,代理实例(组装业务和事务))
//      Proxy.newProxyInstance(loader,interface,h);返回的是一个Object
        GoodService goodService=new GoodServiceImpl();
        Trans trans=new TransImpl();
        MyProxy myProxy=new MyProxy(goodService,trans);
//        getClass()(获取当前对象的所属类对象)getClassLoader()(获取该class对象的类装载器)
        GoodService goodService1=(GoodService) Proxy.newProxyInstance(goodService.getClass().getClassLoader(),goodService.getClass().getInterfaces(),myProxy);
        goodService1.delete();
    }
}
           

四,spring的代理实现

首先需要在spring的配置文件spring-root.xml中启动aop切面代理和注解扫描

<!--启动注解扫描-->
    <context:component-scan base-package="com.study">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"></context:exclude-filter>
    </context:component-scan>
    <!--启动aop切面代理,只有把proxy-target-class改为true才能以cglib的方式,否则是以jdk方式-->
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
           

定义一个aop切面类MyAop(这里要用到两个jar包)

aspectjweaver-1.8.12.jar

官方下载地址

aopalliance-1.0.jar

官方下载地址

用于使用@Aspect(定义切面类)注解

package com.study.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
 * @author: Demon
 * @date: 2019/2/10
 * @time: 19:58
 * Description:切面类(spring 代理的类必须由spring管理)
 */
@Aspect//定义切面类
@Component//被spring管理
public class MyAop {
//    定义切入点(demo1下的任意类,任意方法,任意参数)
    @Pointcut("execution(* com.study.demo1.*.*(..))")
    public void myPointCut(){/**
     *@type method
     *@parameter  []
     *@back  void
     *@author  如花
     *@creattime 2019/2/10
     *@describe 方法中不能做任何操作
     */}
//     目标增强有:前置,后置,环绕
    @Before("myPointCut()")
    public void beforeMethod(){
        System.out.println("这是前置切入");
    }
    @After("myPointCut()")
    public void afterMethod(){
        System.out.println("这是后置切入");
    }
//    环绕
    @Around("myPointCut()")
    public Object tranMethod(ProceedingJoinPoint proceedingJoinPoint){
        Object object=null;
        System.out.println("事务开启");
        try {
            object=proceedingJoinPoint.proceed();
            System.out.println("事务提交");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("事务回滚");
        }//目标方法执行
        return object;
    }
}
           

业务

GoodService :

package com.study.demo1;
import org.springframework.stereotype.Service;
/**
 * @author: Demon
 * @date: 2019/2/10
 * @time: 14:13
 * Description:
 */
@Service
public class GoodService {
    public void save(){
            System.out.println("保存");
    }
}
           

测试

package com.study.demo1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class RunTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("resources/spring-root.xml");
        GoodService goodService=applicationContext.getBean(GoodService.class);
        goodService.save();
    }
}
           
spring框架学习二(aop面向切面编程)
spring框架学习二(aop面向切面编程)
spring框架学习二(aop面向切面编程)

继续阅读