一,什么事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();
}
}