AOP 代理设置模式
概述:
- 所谓代理,就是一个人或某机构代表一个人或某机构采取行动。在一些情况下,客户不想或不能直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中间的作用。
- 通俗讲:
- 经纪人和艺人的关系,经纪人便是代理,艺人就是目标用户,艺人不想做的(安装设备,舞台等),由经纪人去联系处理,这样的模式就是代理模式。
JDK: 静态代理 动态代理 cglib 生成的动态代理
- 静态代理
- 缺点:扩展性差、每次生成新的目标对象类,即使一样,也要重新生成一个代理对象
- 优点:好理解,代码清晰,不复杂
AOP的源码中用到了两种动态代理来实现拦截切入功能
- jdk动态代理和cglib动态代理。
- jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。
- 总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。
定义一个接口
public interface Singer {
//唱歌
public void singing();
//跳舞
public void dancing();
}
实现接口的类
public class ZhangJie implements Singer{
@Override
public void singing() {
System.out.println("正在唱歌");
}
@Override
public void dancing() {
System.out.println("正在跳舞");
}
}
静态代理
//首先要实例化的对象是张杰(也就是我们的目标对象)
Singer singer = new ZhangJie();//多态/向上转型
//实例化代理对象来调用其方法(在调用目标对象前后做相关操作)
ProxyWang proxyWang = new ProxyWang(singer);
proxyWang.singing();
动态代理
//目标对象
Singer singer = new ZhangJie();
//jdk提供了这样一个类,代表代理的意思
//第一个参数是类加载器
//第二个参数是目标对象的class
//第三个参数是代理对象
//返回值类型为Object
Singer s = (Singer) Proxy.newProxyInstance(singer.getClass().getClassLoader(),new Class[]{Singer.class},new ProxyAi(singer));
s.singing();
cglib 生成的动态代理
public class CglibProxy implements MethodInterceptor {
//实例化我们的目标对象
private Object obj;
public Object getObj(Object obj) {
this.obj = obj;
//得到创建代理对象的对象
Enhancer enhancer = new Enhancer();
//设置类加载器
enhancer.setClassLoader(this.obj.getClass().getClassLoader());
//设置其父类
enhancer.setSuperclass(this.obj.getClass());
//设置回调,只要走下面这方法都会走回调
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}
//这个方法就是在你待用目标对象的方法都会执行这个方法
//第一个参数是代理对象/第二个参数是目标对象的方法/第三个参数是目标对象的方法参数/第四个参数是代理对象的拦截方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object ob = null;
if (method.getName().equals("singing")){
System.out.println("设备已经安装成功");
ob = method.invoke(obj, objects);
System.out.println("唱歌结束");
}else if (method.getName().equals("dancing")) {
System.out.println("舞台已经搭建成功,show time");
ob = method.invoke(obj, objects);
System.out.println("舞会结束");
}
return ob;
}
}
//实例化一个cglibProxy 代理对象类
CglibProxy cglibProxy = new CglibProxy();
Singer singer = new ZhangJie();
//这个参数代表我们的目标对象
Singer singer1 = (Singer) cglibProxy.getObj(singer);
singer1.dancing();
Spring AOP的配置元素
设置的步骤
spring 要配置的bean
<bean id="aopError" class="com.offcn.aop.AopError"></bean>
public class AopError {
public void afterError(JoinPoint joinPoint,RuntimeException e){
System.out.println(joinPoint.getSignature().getName()+"这个方法的异常信息"+e.getMessage());
}
public void after(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName());
}
//环绕通知 传递的是 JoinPoint 的子类 ProceedingJoinPoint
public void around(ProceedingJoinPoint proceedingJoinPoint){
System.out.println(proceedingJoinPoint.getTarget()+ Arrays.toString(proceedingJoinPoint.getArgs()));
//调用此方法执行目标对象相应的方法 这个方法相当于一个分割线,也就是前置通知和后置通知的分割线
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println(proceedingJoinPoint.getSignature().getName());
}
}
设置切面、切点、异常,前置,后置,环绕通知
<!-- 设置切面 -->
<aop:config>
<!-- 配置切点 -->
<aop:pointcut id="pointcut" expression="execution(* com.offcn.service.UserService.*(..))"></aop:pointcut>
<!-- 引入增强bean -->
<aop:aspect ref="aopError">
<!-- 配置异常后置增强,这个方法必须引入增强bean的方法, -->
<aop:after-throwing method="afterError" pointcut-ref="pointcut" throwing="e"></aop:after-throwing>
<!-- 后置增强 -->
<aop:after method="after" pointcut-ref="pointcut"></aop:after>
<!-- 前置增强 -->
<aop:before method="after" pointcut-ref="pointcut"></aop:before>
<!-- 环绕增强 -->
<aop:around method="around" pointcut-ref="pointcut"></aop:around>
</aop:aspect>
</aop:config>
测试 Test
public class Test {
@org.junit.Test
public void test(){
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) app.getBean("userService");
userService.add();
}
}
注解前置、后置、环绕、异常通知
@Aspect
public class AopError {
@AfterThrowing(pointcut = "execution(* com.offcn.service.UserService.*(..))",throwing = "e")
public void afterError(JoinPoint joinPoint, RuntimeException e){
System.out.println(joinPoint.getSignature().getName()+"这个方法的异常信息"+e.getMessage());
}
public void after(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName());
}
@Around("execution(* com.offcn.service.UserService.*(..))")
//环绕增强 传递的是 JoinPoint 的子类 ProceedingJoinPoint
public void around(ProceedingJoinPoint proceedingJoinPoint){
System.out.println(proceedingJoinPoint.getTarget()+ Arrays.toString(proceedingJoinPoint.getArgs()));
//调用此方法执行目标对象相应的方法 这个方法相当于一个分割线,也就是前置增强和后置增强的分割线
try {
proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println(proceedingJoinPoint.getSignature().getName());
}
}