一、代理模式
1.何为代理模式
一种java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等
代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务
简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途
2.代理模式的优点
- 优点一:可以隐藏真实目标类的实现;
- 优点二:可以实现客户与真实目标类间的解耦,在不修改真实目标类代码的情况下能够做一些额外的处理
二、静态代理
1.定义
由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成
2.简单实现
①学生接口
public interface IStudent {
public abstract void giveMoney();
}
②学生实现类
public class StudentImpl implements IStudent{
private String name;
public StudentImpl(String name){
this.name = name;
}
@Override
public void giveMoney() {
System.out.println(name + "同学上交了学费");
}
}
③学生代理类
public class StudentProxy implements IStudent {
private IStudent student;
public StudentProxy(IStudent student){
this.student = student;
}
@Override
public void giveMoney() {
//交学费以前可以做的事
before();
student.giveMoney();
//交学费以后可以做的其他事
after();
}
public void before(){
System.out.println("班长替班主任向全班同学收取学费");
}
public void after(){
System.out.println("班长将全班同学的学费交给了班主任");
}
}
④使用静态代理
public class Realize {
private static IStudent student;
private static IStudent studentProxy;
public static void main(String[] args) {
student = new StudentImpl("小明");
studentProxy = new StudentProxy(student);
studentProxy.giveMoney();
}
}
三、动态代理
1.定义
在程序运行时,运用反射机制动态创建而成,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码
2.基于接口的动态代理
(1)如何创建代理对象
使用Proxy类中的newProxyInstance方法
(2)创建代理对象的要求:
被代理类最少实现一个接口,如果没有则不能使用
(3)newProxyInstance方法的参数:
ClassLoader: 类加载器
它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器
固定写法:
[对象].getClass().getClassLoader()
[类].class.getClassLoader()
Class[]: 字节码数组
它是用于让代理对象和被代理对象有相同方法
固定写法:
[对象].getClass().getInterfaces();
[类].class.getInterfaces();
InvocationHandler: 用于提供增强的代码
它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类(不是必须的),此接口的实现类都是谁用谁写
new InvocationHandler(){
/**
* 执行被代理对象的任何方法都会经过invoke方法
* 方法参数的含义:
* proxy ===> 代理对象的引用
* method ===> 当前执行的方法
* args ===> 当前执行方法所需的参数
* return ===> 和被代理对象方法有相同的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
......
}
};
(4)代码实现(方法一:匿名内部类)
①学生接口
public interface IStudent {
public abstract void giveMoney();
}
②接口实现类
public class StudentImpl implements IStudent{
private String name;
public StudentImpl(String name){
this.name = name;
}
@Override
public void giveMoney() {
System.out.println(name + "同学上交了学费");
}
}
③实现动态代理并执行
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Realize {
private static IStudent student;
public static void before(){
System.out.println("班长替班主任向全班同学收取学费");
}
public static void after(){
System.out.println("班长将全班同学的学费交给了班主任");
}
public static void main(String[] args) {
student = new StudentImpl("小明");
IStudent iStudent = (IStudent) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), new InvocationHandler() {
/**
* 执行被代理对象的任何方法都会经过invoke方法
* 方法参数的含义:
* proxy ===> 代理对象的引用
* method ===> 当前执行的方法
* args ===> 当前执行方法所需的参数
* return ===> 和被代理对象方法有相同的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
/**
* invoke方法的参数
* 第一个为被代理对象
* 第二个为方法参数-args
*/
Object obj = method.invoke(student, args);
after();
return obj;
}
});
iStudent.giveMoney();
}
}
(5)代码实现(方法二:自定义类,实现动态代理接口)
①学生接口
public interface IStudent {
public abstract void giveMoney();
}
②接口实现类
public class StudentImpl implements IStudent{
private String name;
public StudentImpl(String name){
this.name = name;
}
@Override
public void giveMoney() {
System.out.println(name + "同学上交了学费");
}
}
③动态代理接口的实现类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class StudentProxy<T> implements InvocationHandler {
private T target;
public StudentProxy(T target){
this.target = target;
}
public void before(){
System.out.println("班长替班主任向全班同学收取学费");
}
public void after(){
System.out.println("班长将全班同学的学费交给了班主任");
}
/**
* 执行被代理对象的任何方法都会经过invoke方法
* 方法参数的含义:
* proxy ===> 代理对象的引用
* method ===> 当前执行的方法
* args ===> 当前执行方法所需的参数
* return ===> 和被代理对象方法有相同的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
/**
* invoke方法的参数
* 第一个为被代理对象
* 第二个为方法参数-args
*/
Object obj = method.invoke(target, args);
after();
return obj;
}
}
④使用动态代理
import java.lang.reflect.Proxy;
public class Realize {
private static IStudent student;
private static StudentProxy studentProxy;
public static void main(String[] args) {
student = new StudentImpl("小明");
studentProxy = new StudentProxy(student);
/**
* newProxyInstance方法的参数:
* ClassLoader: 类加载器
* 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器
* Class[]: 字节码数组
* 它是用于让代理对象和被代理对象有相同方法
* InvocationHandler: 用于提供增强的代码
* 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类(不是必须的),此接口的实现类都是谁用谁写
*/
IStudent iStudent = (IStudent) Proxy.newProxyInstance(student.getClass().getClassLoader(), student.getClass().getInterfaces(), studentProxy);
iStudent.giveMoney();
}
}
3.基于子类的动态代理
1.确保项目是Maven工程
2.在pom.xml中设置打包方式
<packaging>jar</packaging>
3.在pom.xml中导入依赖坐标
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
</dependencies>
4.最终pom.xml为
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>demo19</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
</dependencies>
</project>
5.依赖与使用
依赖类 ===> Enhancer
使用方法 ===> Enhancer.create()
6.要求
被代理类不能是最终类
7.参数
Class ===> 用于指定被代理对象的字节码
Callback ===> 用于提供增强的代码;我们一般写该接口的子接口实现类——>MethodInterceptor
8.代码实现(方法一:匿名内部类)
(1)学生接口
public interface IStudent {
public abstract void giveMoney();
}
(2)学生接口实现类
public class StudentImpl implements IStudent{
private String name;
/**
* 当实现CGLIB代理的时候,如果目标对象没有定义无参构造函数,当Enhancer对象create代理对象的时候,就会报错
* 因为Spring通过CGLIB生成代理类对象时,并没有将目标对象的构造函数的参数及其类型进行设定,导致了CGLIB在生成代理类对象时,会使用默认的构造函数生成,结果目标对象类没有默认构造函数,CGLIB生成子类时,也没有加入默认构造函数,所以,异常的发生成为必然
* 所以这里需要加入默认构造函数
*/
public StudentImpl(){
this.name = null;
}
public StudentImpl(String name){
this.name = name;
}
@Override
public void giveMoney() {
System.out.println(name + "同学上交了学费");
}
}
(3)动态代理的实现
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class Realize {
private static IStudent student;
public static void before(){
System.out.println("班长替班主任向全班同学收取学费");
}
public static void after(){
System.out.println("班长将全班同学的学费交给了班主任");
}
public static void main(String[] args) {
student = new StudentImpl("小明");
/**
* Class ===> 用于指定被代理对象的字节码
* Callback ===> 用于提供增强的代码;我们一般写该接口的子接口实现类——>MethodInterceptor
*/
IStudent iStudent = (IStudent) Enhancer.create(student.getClass(), new MethodInterceptor() {
/**
* 执行被代理对象的任何方法都会经过该方法
* o ===> 代理对象的引用
* method ===> 当前执行的方法
* objects ===> 当前执行方法所需的参数
* methodProxy ===> 当前执行方法的代理对象
* return ===> 和被代理对象方法有相同的返回值
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = method.invoke(student);
after();
return obj;
}
});
iStudent.giveMoney();
}
}
9.代码实现(方法二:自定义接口实现类)
(1).学生接口
public interface IStudent {
public abstract void giveMoney();
}
(2)学生接口实现类
public class StudentImpl implements IStudent{
private String name;
/**
* 当实现CGLIB代理的时候,如果目标对象没有定义无参构造函数,当Enhancer对象create代理对象的时候,就会报错
* 因为Spring通过CGLIB生成代理类对象时,并没有将目标对象的构造函数的参数及其类型进行设定,导致了CGLIB在生成代理类对象时,会使用默认的构造函数生成,结果目标对象类没有默认构造函数,CGLIB生成子类时,也没有加入默认构造函数,所以,异常的发生成为必然
* 所以这里需要加入默认构造函数
*/
public StudentImpl(){
this.name = null;
}
public StudentImpl(String name){
this.name = name;
}
@Override
public void giveMoney() {
System.out.println(name + "同学上交了学费");
}
}
(3)学生代理类
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class StudentProxy<T> implements MethodInterceptor {
private T target;
public StudentProxy(T target){
this.target = target;
}
public void before(){
System.out.println("班长替班主任向全班同学收取学费");
}
public void after(){
System.out.println("班长将全班同学的学费交给了班主任");
}
/**
* 执行被代理对象的任何方法都会经过 intercept方法
* 方法参数的含义:
* o ===> 代理对象的引用
* method ===> 当前执行的方法
* objects ===> 当前执行方法所需的参数
* return ===> 和被代理对象方法有相同的返回值
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = method.invoke(target);
after();
return obj;
}
}
(4)使用动态代理
import net.sf.cglib.proxy.Enhancer;
public class Realize {
private static IStudent student;
private static StudentProxy<IStudent> studentProxy;
public static void main(String[] args) {
student = new StudentImpl("小明");
studentProxy = new StudentProxy<IStudent>(student);
/**
* Class ===> 用于指定被代理对象的字节码
* Callback ===> 用于提供增强的代码;我们一般写该接口的子接口实现类——>MethodInterceptor
*/
IStudent iStudent = (IStudent) Enhancer.create(student.getClass(), studentProxy);
iStudent.giveMoney();
}
}