Spring核心之代理模式

本文详细探讨了Spring中的代理模式,包括静态代理和动态代理。在静态代理中,介绍了如何创建目标对象和代理对象,并通过接口实现进行方法增强。在动态代理部分,讨论了JDK动态代理和CGLIB动态代理的区别,强调JDK动态代理要求目标对象必须实现接口,而CGLIB则通过生成目标对象的子类实现。同时,文章提供了具体的代码实现和测试,以及如何使用工厂模式进行封装。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理实现程序功能的统一维护的一种技术。
AOP的作用:不修改源码的情况下,程序运行期间对方法进行功能增强
好处:1、减少代码的重复,提高开发效率,便于维护。
           2、专注核心业务的开发。
核心业务和服务性代码混合在一起
开发中:各自做自己擅长的事情,运行的时候将服务性代码织入到核心业务中。
通过spring工厂自动实现将服务性代码以切面的方式加入到核心业务代码中。

代理模式

代理:自己不做,找人帮你做。
代理模式:在一个原有功能的基础上添加新的功能。
分类:静态代理和动态代理。

 

首先,新建一个service包,作为业务层,业务层新建代码UserService 

package com.lr.spring.service;

public interface UserService {
    void insert();
}

 再新建一个staticProxy(静态的代理服务器)包,写UserService的实现类放在staticProxy包里

1.代码逻辑

目标对象

package com.lr.spring.staticProxy;

import com.lr.spring.service.UserService;
//目标对象
public class UserServiceImpl implements UserService {
    @Override
    public void insert() {
        System.out.println("目标对象的方法:插入一个User对象");
    }
}

 代理对象

package com.lr.spring.staticProxy;

import com.lr.spring.service.UserService;
//代理对象
public class UserServiceProxy implements UserService {
    //1.注入目标对象,底层我们依然需要去调用目标对象中接口的方法
    private UserService userService;
    //构造方法
    public UserServiceProxy(UserService userService) {
        this.userService = userService;
    }

    //2.需要对目标对象的特定方法进行增强(加上事务),调用目标对象的方法
    @Override
    public void insert() {
        try{
            System.out.println("开启事务");
            userService.insert();//调用目标对象的方法
            System.out.println("提交事务");
        }catch (Exception e){
            System.out.println("回滚事务");
        }finally {
            System.out.println("最终操作");
        }

    }
}

测试目标对象与代理对象

@Test
    public void test01() {
        //目标对象
        UserService userService = new UserServiceImpl();
        userService.insert();
        System.out.println("..................");
        //代理对象
        UserServiceProxy userServiceProxy = new UserServiceProxy(userService);
        userServiceProxy.insert();
    }

面向切面编程思想

AOPAspect Oriented Programming的缩写,意思为面向切面编程,是通过预编译方式和运行期动态 代理实现程序功能的统一维护的一种技术。
AOP的作用:不修改源码的情况下,程序运行期间对方法进行功能增强
好处:1、减少代码的重复,提高开发效率,便于维护。
           2、专注核心业务的开发。
核心业务和服务性代码混合在一起
开发中:各自做自己擅长的事情,运行的时候将服务性代码织入到核心业务中。
通过spring工厂自动实现将服务性代码以切面的方式加入到核心业务代码中。

 
静态代理

.静态代理:代理类由程序员自己编写(代理类会对目标对象的特定方法进行增强)
1)设计接口
原因:代理对象和目标对象都实现同一个功能,比如谦哥,中介都进行租房。
2)编写目标对象(类):实现接口
3)编写代理对象(类):实现接口,注入目标对象,调用其方法,最后增强方法。
缺点:每次编写一个目标类的时候,都需要重新去编写(至少)一个代理类,太麻烦了,我们希望由系统帮咱们生成代理对象。

1.新建一个TranAop切面类,把固有的几种操作封装起来

package com.lr.spring.Aop;

public class TranAop {
    public void before(){
        System.out.println("开启事务");
    }
    public void after(){
        System.out.println("提交事务");
    }
    public void exception(){
        System.out.println("回滚事务");
    }
    public void myFinally(){
        System.out.println("最终的操作");
    }
}

 2.实现类

package com.lr.spring.staticProxy;

import com.lr.spring.Aop.TranAop;
import com.lr.spring.service.UserService;

public class UserServiceProxyAopImpl implements UserService {

    public UserService userService;
    public TranAop tranAop;

    public UserServiceProxyAopImpl(UserService userService, TranAop tranAop) {
        this.userService = userService;
        this.tranAop = tranAop;
    }

    @Override
    public void insert() {
        try{
            tranAop.before();
            userService.insert();//调用目标对象的方法
            tranAop.after();
        }catch (Exception e){
            tranAop.exception();
        }finally {
            tranAop.myFinally();
        }
    }
}

3.测试结果

  @Test
    public void test02(){
        TranAop aop=new TranAop();
        UserServiceImpl userService=new UserServiceImpl();
        UserServiceProxyAopImpl userServiceProxyAop=new UserServiceProxyAopImpl(userService,aop);
        userServiceProxyAop.insert();
    }

动态代理

1.常见问题

1.什么是动态代理?

程序运行的时候,根据要被代理分对象动态生成代理类
代理类不需要程序员自己去编写,由系统提供,我们只需要关注业务方法的功能增强(处理)

2.动态代理的分类:

jdk动态代理和cglib动态代理。

3.jdk动态代理(重点)和cglib动态代理有什么区别?

1.jdk动态代理

(1).要求目标对象必须实现接口

(2).Proxy(代理类) public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){ }

该方法可以为任何实现了接口的对象提供代理对象,而且可以针对目标对象实现的接口中的方法进行增强

参数ClassLoader loade(类加载器)

参数Class<?>[] interfaces:目标对象接口的实现(为什么用数组?可以多实现)

参数InvocationHandler h:回调,接口,处理(增强)目标对象接口中的方法。

public interface InvocationHandler {
     public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable;//自己需要编写的部分
}

method指代理目标对象接口中的方法,使用的时候,往往method.inveke(目标对象,参数)

(3).Method public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { }

功能:调用当前对象的方法,obj:对象。args:参数

2.cglib动态代理:

cglib代理生成目标对象的子类对象(底层在内存中生成了该目标对象的子类对象),会对目标对象中所有的方法都进行增强(处理)

cglib代理被称为子类代理

1.特点:目标对象不需要实现接口,就可以提供其代理对象

注意:对特殊方法(final),无法处理。

2.hibernate和spring底层广泛使用到了cglib代理,但是面试的时候一般问jdk为主。

3.核心方法

Enhancer:核心类,提供目标对象的子类对象

create():静态方法,提供代理对象,等价于Proxy的newProxyInstance MethodInterceptor接口

intercept:抽象方法,对目标对象方法的增强

2.代码实现

1.UserService

package com.lr.spring.service;

public interface UserService {
    void undateUser();
    void inserUser(String name);
    String findUserById(int id);
}

目标对象实现类

package com.lr.spring.service;
//目标对象(类)
public class UserServiceImpl implements UserService {
    @Override
    public void undateUser() {
        System.out.println("修改操作");
    }

    @Override
    public void inserUser(String name) {
        System.out.println("插入操作:"+name);
    }

    @Override
    public String findUserById(int id) {
        System.out.println("查询操作,根据id"+id+"进行查询");
        return "user:"+id;
    }
}

测试自动生成代理对象

package com.lr.spring;

import com.lr.spring.service.UserService;
import com.lr.spring.service.UserServiceImpl;
import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


public class AppTest {
    @Test
    public void test01() {
        //在回调中使用外接的对象,该对象需要使用final修饰
        final UserService userService = new UserServiceImpl();
        //自动生成代理类的方法
        UserService userService2 = (UserService)Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        Object result = method.invoke(userService, args);// 调用目标对象的底层(接口中的)方法
                        return result;
                    }
                }
        );
        System.out.println(userService2.getClass());
        String user = userService2.findUserById(100);
        System.out.println(user);
        userService2.undateUser();
        userService2.inserUser("龙仁");
    }
}

 

 此刻还没有对目标对象的方法进行增强

测试对目标对象的方法增强

package com.lr.spring;

import com.lr.spring.service.UserService;
import com.lr.spring.service.UserServiceImpl;
import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


public class AppTest {
    @Test
    public void test01() {
        //在回调中使用外接的对象,该对象需要使用final修饰
        final UserService userService = new UserServiceImpl();
        //自动生成代理类的方法
        UserService userService2 = (UserService)Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法名中以find开头的方法,都不加人事务管理
                        if(method.getName().startsWith("find")){
                            Object obj = method.invoke(userService,args);
                            return obj;
                        }else{
                        try {
                            System.out.println("开启事务");
                            Object result = method.invoke(userService, args);// 调用目标对象的底层(接口中的)方法
                            System.out.println("提交事务");
                            return result;
                        } catch (Exception e) {
                            System.out.println("回滚事务");
                            throw e;//这里尽量不要用return null,否则放在真实环境中会报空指针异常
                        }finally {
                            System.out.println("最终结果");
                        }
                    }
                }
            }
        );
        System.out.println(userService2.getClass());
        String user = userService2.findUserById(100);
        System.out.println(user);
        userService2.undateUser();
        userService2.inserUser("龙仁");
    }
}

 3.使用工厂模式对其封装

1.新建切面类,封装方法

package com.lr.spring.aop;

public class TranAop {
    public void before(){
        System.out.println("开启事务");
    }
    public void after(){
        System.out.println("提交事务");
    }
    public void exception(){
        System.out.println("回滚事务");
    }
    public void myFinally(){
        System.out.println("最终的操作");
    }
}

2.新建工厂类,封装方法

package com.lr.spring.jdkProxy;

import com.lr.spring.aop.TranAop;
import com.lr.spring.service.UserService;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxyFactory {
    //属性:目标对象(接口),切面类TranAop
    private UserService userService;
    private TranAop aop;

    public JdkProxyFactory(UserService userService, TranAop aop) {
        this.userService = userService;
        this.aop = aop;
    }
//工厂方法:提供代理对象
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result = null;//标记思想
                        if (method.getName().startsWith("find")){
                            method.invoke(userService,args);
                        }else{
                            try{
                                aop.before();
                                Object obj = method.invoke(userService,args);
                                aop.after();
                                return obj;
                            }catch (Exception e){
                                aop.exception();
                                throw e;
                            }finally {
                                aop.myFinally();
                            }
                        }
                        return result;
                    }
                });
    }
}

 3.测试程序

@Test
    public void test02() {
        UserService userService = (UserService) new JdkProxyFactory(new UserServiceImpl(), new TranAop()).getProxyInstance();
        userService.inserUser("龙仁");
        userService.undateUser();
        userService.findUserById(100);
    }

 

4.子类代理 

1.创建目标对象/类

package com.lr.spring.service;
//目标对象
public class EmpService {
    public void updateEmp(String name){
        System.out.println("修改操作");
    }
    public void deleteEmo(int id){
        System.out.println("删除对象");
    }
}

2.直接进行测试(不需要实现任何接口)

 @Test
    public void test03(){
        EmpService empService=new EmpService();
        EmpService empService2= (EmpService) Enhancer.create(empService.getClass(),
                new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        System.out.println("目标对象方法的增强");
                        Object result = methodProxy.invokeSuper(o,objects);//调用目标对象底层方法
                        return result;
                    }
                });
        System.out.println(empService2);
        //验证底层方法是否实现
        empService2.updateEmp("龙仁");
        empService2.deleteEmo(100);
    }

 

3.使用切面类进行封装

 public void test03(){
        EmpService empService=new EmpService();//目标对象
        EmpService empService2= (EmpService) Enhancer.create(empService.getClass(),
                new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        try{
                            System.out.println("开启事务");
                            Object result = methodProxy.invokeSuper(o,objects);//调用目标对象底层方法
                            System.out.println("提交事务");
                            return result;
                        }catch (Exception e){
                            System.out.println("回滚事务");
                            throw e;
                        }finally {
                            System.out.println("最终结果");
                        }
                    }
                });
        System.out.println(empService2);
        //验证底层方法是否实现
        empService2.updateEmp("龙仁");
        empService2.deleteEmo(100);
    }

4.使用工厂模式

   public Object geiProxyIntance(){
        return Enhancer.create(empService.getClass(),
                new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        try{
                            tranAop.before();
                            Object result = methodProxy.invokeSuper(o, objects);
                            tranAop.after();
                            return result;
                        }catch (Exception e){
                            tranAop.exception();
                            throw e;
                        }finally {
                            tranAop.myFinally();
                        }
                    }
                });
    }

测试程序

@Test
    public void test04(){
        TranAop aop=new TranAop();
        EmpService empService=new EmpService();
        EmpService empService2= (EmpService)new CglibProxyFactory(empService,aop).geiProxyIntance();
        empService2.updateEmp("龙傲天");
        empService2.deleteEmo(3);
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值