프록시 모드 : 해결해야 할 주요 문제는 특정 리소스에 대한 액세스와 사용하기 쉬운 객체 클래스 작업을위한 편리한 프록시 서비스를 제공하는 것입니다.
사용할 장면 :
- 서비스 확장 중 데이터베이스 연결 수의 갑작스런 증가를 줄이기 위해 데이터베이스 액세스 수준을 통해보다 기본적인 애플리케이션을 제공합니다.
- 일부 미들웨어 : RPC 프레임 워크. jar 패키지의 인터페이스 설명을 얻은 후 미들웨어는 서비스 시작시 해당 프록시 클래스를 생성하고, 인터페이스가 호출되면 소켓 정보가 실제로 프록시 클래스를 통해 전송됩니다.
- MyBatis는 기본적으로 인터페이스를 정의하지만 구현 클래스를 작성할 필요가 없으며 mapper.xml이나 Annotation에서 SQL 문을 추가, 삭제, 수정, 확인할 수 있습니다.
구조:
- 추상 테마 역할 : 실제 테마와 에이전트 테마 간의 공통 인터페이스를 선언합니다.
- 상담원 테마 역할 : 내부에는 실제 테마 및 상담원 테마에 대한 공통 인터페이스가 포함됩니다.
- 실제 테마 역할 : 실제 개체를 정의합니다.
Spring AOP는 동적 프록시 기반입니다 . 프록시 대상 객체가 특정 인터페이스를 구현하면 Spring AOP는 JDK 프록시 를 사용하여 프록시 객체를 생성합니다. 인터페이스를 구현하지 않는 객체의 경우 JDK 프록시를 프록시에 사용할 수 없습니다. 시간은 스프링 AOP가 사용 CGLIB를 이 때, 스프링 AOP가 사용합니다. 하는 CGLIB를 다음 그림과 같이 프록시와 프록시 객체의 하위 클래스를 생성합니다 :
물론 AspectJ를 사용할 수도 있습니다. Spring AOP는 AspectJ 를 통합 했으며 AspectJ는 자바 생태계에서 가장 완벽한 AOP 프레임 워크로 간주되어야합니다.
확장-Spring AOP와 AspectJ AOP의 차이점
JDK의 동적 프록시
InvocationHandler中的invoke()方法属于代理类中调用真实主题类的方法,但是该方法没有所对应的真实主题类,需要在创建对象时设置真实主题。
package java.lang.reflect; public interface InvocationHandler { /** * Object proxy:代理类的对象[代理后的类] * Method method:需要调用的方法 * Object[] args:方法所需的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
프록시 객체를 가져 오려면 java.lang.reflect.Proxy 클래스를 사용하여 동적으로 생성해야합니다.
/** * ClassLoader loader:取得对象的加载器 * Class<?>[] interfaces:代理模式的核心是围绕接口进行的,所以需取出全部接口 * InvocationHandler h:代理实现类 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
예 1 :
// 简单Java类
public class Dept {
}
// 定义的接口层
public interface IDeptDAO {
boolean doCreate(Dept vo) throws Exception;
List<Dept> findAll() throws Exception;
}
// 具体接口实现
public class DeptDAOImpl implements IDeptDAO{
@Override
public boolean doCreate(Dept vo) throws Exception {
System.out.println("执行数据增加操作");
return false;
}
@Override
public List<Dept> findAll() throws Exception {
System.out.println("执行数据查询操作");
return null;
}
}
//动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DAOProxy implements InvocationHandler {
// 不能与具体的DAO耦合在一起
private Object obj ; // 真实主题类--需要代理的
/**
* 将真实主题类绑定到代理中,返回一个被代理后的对象
* @param obj 真实主题类
* @return 代理后的对象
*/
public Object bind(Object obj){
// !!!!要保存真实主题类--便于后面的方法执行!!!!
this.obj = obj ;
/**
* -----由Java系统实现的代理
* obj.getClass().getClassLoader() : 通过反射取得该真实主题类的类加载器
* obj.getClass().getInterfaces() : 通过反射取得真实主题的所有接口
* this: 由于当前DAOProxy实现了InvocationHandler,所以是代理类
*/
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
public void prepare(){
System.out.println("*************取消JDBC的自动提交***************");
}
public void commit(){
System.out.println("*************手动提交JDBC事务***************");
}
public void rollback(){
System.out.println("*************手动回滚JDBC事务***************");
}
// 只要执行了方法,就会触发执行invoke()方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null ; // 接收结果
if (method.getName().contains("do")){
// 取得方法的名称对操作进行判断
this.prepare();
try {
// 反射中的知识--执行方法需要存在类的实例所以要保存this.obj
result = method.invoke(this.obj, args);
this.commit();
} catch (Exception e){
e.printStackTrace();
rollback();
}
} else{
// 如果不需要开启事务,则直接执行方法
result = method.invoke(this.obj, args);
}
return result;
}
}
// 通过工厂类隐藏具体细节
public class DAOFactory {
public static Object getDAOInstance(){
// 直接将真实主题类绑定到代理中返回代理后的类
return new DAOProxy().bind(new DeptDAOImpl());
}
}
//测试类
public class ProxyMain {
public static void main(String[] args) throws Exception{
IDeptDAO dao = (IDeptDAO) DAOFactory.getDAOInstance();
Dept dept = new Dept();
dao.doCreate(dept);
dao.findAll();
}
}
/* output:
* *************取消JDBC的自动提交***************
* 执行数据增加操作
* *************手动提交JDBC事务***************
* 执行数据查询操作
* /
CGLIB 동적 에이전트
CGLIB는이 패키지 를 사용하여 인터페이스없이 동적 프록시 디자인 패턴 을 구현합니다.
CGLIB는 강력한 고성능 코드 생성 라이브러리입니다. AOP 프레임 워크 (Spring, dynaop)에서 메서드 차단 작업을 제공하기 위해 널리 사용됩니다. 더 많이 사용되는 ORM 프레임 워크 인 Hibernate는 CGLIB를 사용하여 단일 종단 (다 대일 및 일대일) 연결 (지연된 컬렉션에서 사용되는 또 다른 메커니즘)을 프록시합니다.
CGLIB를 사용하는 경우 해당 관계가 명확해야합니다.
- 프록시-> net.sf.cglib.proxy.Enhancer;
- InvocationHandler-> net.sf.cglib.proxy.MethodInterceptor;
- 실제 테마 호출 : net.sf.cglib.proxy.MethodProxy
package 代理设计模式;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
class FunctionImple{
public void create(){
System.out.println("create方法");
}
}
class MyProxy implements MethodInterceptor{
private Object object; // 真实操作主题类
public MyProxy(Object object){
this.object = object;
}
public void prepre(){
System.out.println("取消自动提交");
}
public void commit(){
System.out.println("提交进行事务操作");
}
public void rollback(){
System.out.println("提交失败,回滚");
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object reuslt = null;
// 说明proxy是真实类的子类--如果被代理类是Final类就无法使用CGLIB
// 但是ASM可以对Final进行代理
System.out.println(proxy.getClass().getSuperclass().getName());
this.prepre();
// CGLIB反射调用真实对象方法
reuslt = methodProxy.invokeSuper(proxy, args);
this.commit();
return reuslt;
}
}
public class CGLIBDemo {
public static void main(String[] args) {
// 真实主题对象
FunctionImple functionImple = new FunctionImple();
// CGLIB enhancer增强类对象
Enhancer enhancer = new Enhancer();
// 设置增强类型--是当前类的子类
enhancer.setSuperclass(FunctionImple.class);
// 定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
enhancer.setCallback(new MyProxy(functionImple));
// 生成并返回代理对象
FunctionImple proxyDao = (FunctionImple) enhancer.create();
proxyDao.create();
}
}
/**
* 代理设计模式.FunctionImple
* 取消自动提交
* create方法
* 提交进行事务操作
*/