【Spring】代理模式 与 Spring中的jdk动态代理和cglib动态代理

代理模式:

代理模式的定义:代理模式(Proxy Pattern)是程序设计中的一种设计模式。为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式的组成

  • 1、抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
  • 2、真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
  • 3、代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

代理的分类

  • 静态代理:在程序运行之前就已经确定代理类与其代理的真实类。例如,在编写程序时,指定一个接口A。类B实现A接口完善其逻辑代码。类C也实现了A接口,但是其并没有自己的逻辑代码,而是引用了类B的逻辑代码,类C也可以在其引用的类B的逻辑代码的基础上做一些其他操作。此时,就称类C是类B的静态代理。
  • 动态代理:在程序运行时才确定代理类,动态代理目前有两种常见的实现:jdk动态代理和cglib动态代理。

Spring AOP中隐含的动态代理:

一:Spring AOP中使用jdk动态代理:

想要在spring中使用jdk代理,需要以下几个条件:
1、定义一个接口,例:

package cn.jingpengchong.math.service;

public interface IMathService {
	int div(int a, int b);
}

2、定义一个实现该接口的类,例:

package cn.jingpengchong.math.service;

import org.springframework.stereotype.Service;
//使用spring自动实例化对象,需添加能够被扫描到的特定注解
@Service
public class MathService implements IMathService {
	public int div(int a, int b) {
		System.out.println("日志:The div method begins");
		return a/b;
	}
}

3、在spring的xml配置文件中做如下配置

<!--假如不写proxy-target-class属性则默认是false-->
<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>

4、定义切面,并且切入点要有与真实类相匹配的增强处理,例:

package cn.jingpengchong.math.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
//该注解指定该类为切面类
@Aspect
//使用spring自动实例化对象,需添加能够被扫描到的特定注解
@Component
public class MethodAOP {
	
	//前置处理,表达式要与真实类的某个方法匹配,否则无法生成代理类
	@Before("execution(public int cn.jingpengchong.math.service.MathService.*(..))")
	public void before() {
	//此处可以添加附加操作
	}
}

5、通过接口对应的Class类的实例化对象获得代理类,例:

package cn.jingpengchong.math.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.jingpengchong.math.service.IMathService;
import cn.jingpengchong.math.service.MathService;

public class Test {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
		//此处不能通过真实类对应的Class类的实例化对象获得代理类
		IMathService mathService = applicationContext.getBean(IMathService.class);
		System.out.println("mathService的类是:");
		System.out.println(mathService.getClass());
		System.out.println("mathService的父类是:");
		System.out.println(mathService.getClass().getSuperclass());
		Class<?>[] interfaces = mathService.getClass().getInterfaces();
		System.out.println("mathService的类实现的接口有:");
		for (Class<?> c : interfaces) {
			System.out.println(c);
		}
		applicationContext.close();
	}
}

运行结果如下,顺便可以观察以下代理类的类、父类及实现的接口
在这里插入图片描述
假如没有第3步所做的配置,则运行结果如下:
在这里插入图片描述
假如第4步的切面中没有一个表达式与真实类中任何一个方法匹配,则结果如下:
在这里插入图片描述
假如第5步用真实类对应的Class类的实例化对象获得代理类,则结果如下:
在这里插入图片描述

二、Spring AOP中使用cglib动态代理:

Spring中使用cglib动态代理与jdk代理类似,不同之处在于:
1、将spring的xml配置文件中的aop:aspectj-autoproxy标签的proxy-target-class属性值改为true;
2、既可以通过接口对应的Class类的实例化对象获得代理类,也可以通过真实类对应的Class类的实例化对象获得代理类。

  • 通过两种方式获得代理类的结果是一样的:
    在这里插入图片描述

三、jdk动态代理和cglib动态代理的区别:

1、jdk动态代理基于接口实现,而cglib动态代理基于真实类实现;
2、jdk动态代理间接实现接口,与真实类没有继承关系,而cglib动态代理则直接继承了真实类。

Spring的事务管理自动使用动态代理:

除了在AOP中我们发现了动态代理的存在,其实在spring的事务管理中也用到了动态代理,Spring会将添加了@Transactional注解的类创建代理类,尽管我们在Spring的xml配置文件中并没有配置aop:aspectj-autoproxy标签。例如在下面的例子中:

扫描二维码关注公众号,回复: 9384883 查看本文章
package cn.jingpengchong.car.service;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.jingpengchong.coupon.service.ICouponService;

@Service
public class CarService implements ICarService {

	@Autowired
	private ICouponService couponService;

	//购物车购买
	@Transactional
	@Override
	public boolean batch(String userId,Map<String,Integer> commodities) {
		Set<Entry<String, Integer>> set = commodities.entrySet();
		for (Entry<String, Integer> commodity : set) {
			String bookId = commodity.getKey();
			int count = commodity.getValue();
			System.out.println(bookId+","+count);
			couponService.insert(userId,bookId, count);
		}
		return true;
	}
}

并且在spring的xml文件中也没有配置aop:aspectj-autoproxy标签,但是当我们写个测试类如下:

package cn.jingpengchong.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.jingpengchong.coupon.service.ICouponService;

public class Test01 {

	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
		ICouponService couponService = applicationContext.getBean(ICouponService.class);
		System.out.println("couponService的类是:");
		System.out.println(couponService.getClass());
		System.out.println("couponService的父类是:");
		System.out.println(couponService.getClass().getSuperclass());
		Class<?>[] interfaces = couponService.getClass().getInterfaces();
		System.out.println("mathService的类实现的接口有:");
		for (Class<?> c : interfaces) {
			System.out.println(c);
		}
		applicationContext.close();
	}
}

发现结果还是使用了动态代理,观察代理类的类名我们可以清楚的知道这是一个jdk动态代理,因为其标志性字眼“Proxy”:
在这里插入图片描述

发布了128 篇原创文章 · 获赞 17 · 访问量 2724

猜你喜欢

转载自blog.csdn.net/qq_43705275/article/details/104245370