Java 结合实例学会使用 静态代理、JDK动态代理、CGLIB动态代理

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Java 结合实例学会使用 静态代理、JDK动态代理、CGLIB动态代理

前言



代理 代理 代理 代理 代理 代理 代理 代理 代理 代理

代理 代理 代理 代理 代理 代理 代理 代理 代理 代理


很多人至今都是看到 代理就懵, 静态代理、动态代理、JDK动态代理、CGLIB动态代理......


知道AOP,知道增强,但是还是对代理模式支支吾吾? 这是因为你没有用心去了解过它......


您这种症状持续多久了?

现在看这篇文章,还来得及。

该篇文章咱们将会一起通过手敲实例代码,去了解和使用代理模式,实现静态代理、JDK动态代理、CGLIB动态代理。

实现完再回头看看,应该就不会支支吾吾了。


进入正文



一、代理模式


代理模式分为:


静态代理  


动态代理


先不管什么静还是动的,先知道这个代理模式的使用,是干嘛的。


文字描述:


为其他对象提供一个代理以控制对某个对象的访问。

代理类主要负责为委托了(真实对象)预处理消息、过滤消息、传递消息给委托类,代理类不现实具体服务,而是利用委托类来完成服务,并将执行结果封装处理。


听我说:

其实就是 在你调用 某个业务方法时, 在调用前 和调用后,加点东西。


加的这些东西 随时改动,也不会影响到业务方法代码的改动。 这样就很 解耦 ,就很喜欢。


就像, 调用某个业务方法前, 我加个 日志记录(记录一下调用的方法、参数、IP来源等等);


又比如说,调用某个业务方法前,我加个 权限拦截 (看看能不能给调用,判断一下token、身份、角色、ip等等)


从代理模式的实现效果来说,就是做到了2点:


1、可以对 业务代码(需要被代理的类)  进行  增强(附属一些逻辑代码)


2、实现代理之后 ,主业务方法不用动, 需要新增的,修改调整的一些业务,可以都丢到代理方法里面去做,这样一定程度实现了代码防入侵。


image.png

二、实例讲解


该篇文章使用到的实例是一个 我自己临时模拟的场景:


业务-  点餐下单


然后 运用上代理模式,实现添加一些 点餐下单 前前后后的  代码,记录日志、权限判断等等。


1.静态代理


1.1 就像往常一样,我们先写个接口 OrderService:


import java.util.Map;
/**
 * @Author : JCccc
 * @CreateTime : 2020/4/16
 * @Description :
 **/
public interface OrderService {
    //下单点餐
    Map executeFoodOrder(String userName,Map<String, Integer> foodMap);
}


1.2 就像往常一样,接口 OrderService的实现类 OrderServiceImpl:


import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
 * @Author : JCccc
 * @CreateTime : 2020/4/16
 * @Description :
 **/
@Service
public class OrderServiceImpl implements OrderService {
    @Override
    public  Map executeFoodOrder(String userName,Map<String, Integer> foodMap) {
        System.out.println("*********【下单主业务】*********");
        Map resultMap=new HashMap();
        for (Map.Entry<String, Integer> m : foodMap.entrySet()) {
            String foodName=m.getKey();
            Integer foodCount= m.getValue();
            //模拟一些杂七杂八的业务
            System.out.println("【下单主业务】"+foodName+"---模拟这个菜的一些杂七杂八的业务");
            resultMap.put(foodName,"ok");
        }
        return resultMap;
    }
}


1.3 现在我们有个业务需求,就是记录客户点餐信息,根据传入的用户名,去数据库查出来,然后跟点的菜啥的简单做个日志记录。


那么静态代理的方式是这样实现(这里介绍的是通过实现业务接口方式,而其实还可以简单通过继承来实现):


静态代理类   OrderServiceLogProxy.java :


import com.ilas.testboot.proxy.OrderService;
import java.util.Map;
/**
 * @Author : JCccc
 * @CreateTime : 2020/4/21
 * @Description :
 **/
public class OrderServiceLogProxy implements OrderService {
    private OrderServiceImpl orderService;
    public OrderServiceLogProxy(OrderServiceImpl orderService) {
        this.orderService = orderService;
    }
    @Override
    public Map executeFoodOrder(String userName, Map<String, Integer> foodMap) {
        System.out.println("+静态代理LogProxy");
        System.out.println("+下单前我们做点什么.");
        System.out.println("+正在获取用户:"+userName+"用户信息......");
        System.out.println("+正在记录用户:"+userName+"选择的菜品:"+foodMap.toString());
        System.out.println("+准备执行主业务");
        Map map = orderService.executeFoodOrder(userName, foodMap);
        System.out.println("+下单后我们做点什么.");
        System.out.println("+记录用户"+userName+"下单后的详情信息:"+map.toString());
        return map;
    }
}


简单分析下,我们新创建了一个实现下单点餐接口的类,在这类里面,重写下单方法executeFoodOrder,在调用下单方法时加上一些日志记录等等的代码:


image.png


OK,有可能这样写,你还是不能看出所为的代理结构,那么如果说我 写成这样呢?


是不是这样看起来就有感觉了。(该篇文章后面的JDK动态代理、CGLIB动态代理,我就不一一抽出来写成 before和 after了)


image.png


调用方式:


public static void main(String[] args) {
        //静态代理调用方式
        OrderServiceImpl orderService=new OrderServiceImpl();
        OrderServiceLogProxy orderServiceLogProxy=new OrderServiceLogProxy(orderService);
        String userName="JCccc";
        Map<String,Integer> orderMap=new HashMap<>();
        orderMap.put("白米饭",2);
        orderMap.put("红烧肉",1);
        orderMap.put("水煮鱼",1);
        orderMap.put("番茄炒蛋",1);
        Map resultMap = orderServiceLogProxy.executeFoodOrder(userName, orderMap);
        System.out.println("静态代理方法执行完毕,结果:"+resultMap);
    }


可以看下控制台的输出情况:


蓝色:静态代理类做的事情 (可以看到在主业务执行的前后)


红色:原本主业务做的事情


image.png


静态代理使用感觉:


实现代理的代码都是提前设计好,而且还是一一对应起来,OrderService 的代理是 OrderServiceLogProxy;


而且实现代理的方法也是一一对应。


那么如果 需要记录日志 的不止是OrderService ,再来一个 UserService呢? 再来一个 GameService呢?


这样一来,需要我们写死的代码就非常非常多。


这就是所谓的 静态 的不好之处,于是乎有了 动态代理(能够根据我们传入的 需要被代理类,实现代理)。


2.动态代理

动态代理有两种:


JDK动态代理


CGLIB动态代理


2.1 JDK动态代理


基于前面创建好的 OrderService 和 OrderServiceImpl ,我们接下来采取 JDK动态代理的方式去实现我们的日志添加。


(已经有种解耦的意味了吧,我们根本不需要动原本的业务接口和业务实现类,代理模式的作用无形中已经慢慢崭露出来了)


创建咱们的日志动态代理类,DynamicsLogProxy.java :


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
/**
 * @Author : JCccc
 * @CreateTime : 2020/4/21
 * @Description :
 **/
public class DynamicsLogProxy implements InvocationHandler {
    Object obj;
    //绑定委托对象,并返回代理类
    public Object bind(Object obj)
    {
        this.obj = obj;
        //绑定该类实现的所有接口,取得代理类
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("+静态代理LogProxy");
        System.out.println("+下单前我们做点什么.");
        System.out.println("+正在获取目前传入的参数:"+Arrays.toString(args));
        System.out.println("+正在记录.....");
        System.out.println("+准备执行主业务");
        Object res = method.invoke(obj, args);
        System.out.println("+下单后我们做点什么.");
        System.out.println("+可得到业务方法执行后结果"+res.toString());
        System.out.println("+记录.......");
        return res;
    }
}


JDK动态代理的一些代码剖析:


1. JDK动态代理类 必须 实现 InvocationHandler 接口:


image.png


2.被代理的类 必须 存在 类 和实现的接口 (OrderService  和  OrderServiceImpl)


3.需要把 被代理对象传过去,因为动态生成代理类时要使用到:


image.png


3.使用jdk的api 中的 java.lang.reflect.Proxy 帮我们即时创建 代理实例对象:


image.png


image.png


前面两个参数,可以理解为把需要被代理的类相关信息传过去,最后一个参数  InvocationHandler h,


这玩意讲究。


image.png


咱们的DynamicsLogProxy 实现了这玩意,那么Proxy帮我们创建出来的一个代理实例对象,自然是不清楚咱们要代理的具体方法。


而invoke就是帮我们根据传入的参数:


proxy表示动态代理类实例,method表示调用的方法,args表示调用方法的参数


实现 调用 目标对象(被代理的类)的 目标方法。


简单点理解:


Proxy会帮我们 动态创建一个代理类,  这个代理类 代理的谁, 是我们传入的。


而InvocationHandler 的invoke方法,随时待命从代理类中去调用 被代理类的对应方法。


调用方式:


public static void main(String[] args) {
        //动态代理调用方式
        OrderService dynamicsOrderProxy = (OrderService)new DynamicsLogProxy().bind(new OrderServiceImpl());
        String userName="JCccc";
        Map<String,Integer> orderMap=new HashMap<>();
        orderMap.put("白米饭",2);
        orderMap.put("红烧肉",1);
        orderMap.put("水煮鱼",1);
        orderMap.put("番茄炒蛋",1);
        //通过动态代理类去调用不同方法
        Map resultMap = dynamicsOrderProxy.executeFoodOrder(userName, orderMap);
        System.out.println("动态代理方法执行完毕,结果:"+resultMap);
    }


可以看下控制台的输出情况:


image.png


JDK的动态代理使用感觉:


挺好,我们只需要编写一个日志代理类之后;


想这个日志代理类与哪个 需要被代理的类绑定, 我们就动态传入;


想要在被代理的类哪个方法前后 去嵌入 一些东西, 我们就动态调用方法;


很灵活,不像静态代理那样死死的。


但是,显然我们在使用JDK动态代理的时候,我们发现了,Proxy在帮我们动态即时创建 代理类的时候,要求我们传入


Class<?>[] interfaces  


那就是意味着,我们的需要被代理的类,必须实现接口:


image.png


因为JDK动态代理其实也是悄咪咪帮我们创建一份代理类代码,也帮我们实现同样的接口。


也就是说, 如果你的 被代理类, 没有实现接口,那么就没办法使用 JDK动态代理。


那怎么办?  CGLIB动态代理出来了,它说 我不关心你是否实现接口,只需要告诉我 哪个类需要被代理。


2.2 CGLIB动态代理


上面咱们已经说了,CGLIB动态代理只关心 哪个类需要被代理。


因为这个家伙其实是悄咪咪地帮我们 针对需要被代理的类 创建一个 代理子类。根据调用的方法,拦截调用到父类的方法。


看CGLIB动态代理实现,CglibLogProxy.java:


import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
 * @Author : JCccc
 * @CreateTime : 2020/4/21
 * @Description :
 **/
public class CglibLogProxy  implements MethodInterceptor {
    /**
     * 自定义方法:利用Enhancer类生成代理类
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T getObjByEnhancer(Class<T> clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        T res = (T) enhancer.create();
        return res;
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(" +CGLIB日志代理CglibLogProxy");
        System.out.println("+CGLIB日志代理获取到执行的方法名" + method.getName());
        System.out.println("+做一些日志记录......");
        System.out.println("+做一些日志记录...");
        Object res = methodProxy.invokeSuper(o, objects);
        System.out.println("+主业务方法执行后我们做点什么.");
        System.out.println("+可得到业务方法执行后结果"+res.toString());
        System.out.println("+记录.......");
        return res;
    }
}


实现代码简单剖析:


1. implements MethodInterceptor    cglib动态代理类实现了这个方法拦截


2. intercept 方法,这个也就是 提供地方给咱们 添加 日志记录、权限判断等等的地方


3. Enhancer


Enhancer  这个玩意是CGLIB动态代理类的核心。


它的职责是,创建出一个子类(代理类), 然后将我们传入的 被代理类  设置成 SuperClass 父类 。


这个子类(代理类) ’继承‘ 了父类( 被代理类)的 所有 可以公开的方法 ,然后设置拦截回调的类(父类),子类中拦截父类方法并织入方法增强逻辑。


ps:cglib动态代理不能代理声明为final类型的类和方法  


事不宜迟,我们贴出CGLIB动态代理调用方式:


public static void main(String[] args) {
        CglibLogProxy  cglibLogProxy=new CglibLogProxy();
        OrderServiceImpl   orderProxy=   cglibLogProxy.getObjByEnhancer(OrderServiceImpl.class);
        String userName="JCccc";
        Map<String,Integer> orderMap=new HashMap();
        orderMap.put("白米饭",2);
        orderMap.put("红烧肉",1);
        orderMap.put("水煮鱼",1);
        orderMap.put("番茄炒蛋",1);
        Map map = orderProxy.executeFoodOrder(userName, orderMap);
        System.out.println(map.toString());
    }


注意看, 调用方法的时候,用的是什么?


orderProxy.executeFoodOrder(userName, orderMap);


没错,跟JDK动态代理看似一样直接调用 我们执行的业务方法,


但是接下来就不一样了,再看看cglib动态代理类的实现代码:


image.png


没错,orderProxy是我们通过Enhancer去生成的,特意设置了回调拦截方法。从拦截的这个意思去看,就更有AOP的意味,更有代理的感觉了。


调用父类方法(被代理类)前,拦住, 先调用咱们自己写的 拦截方法, 啥时候完事了,再通过 methodProxy.invokeSuper 切回到主业务方法去。


可以看到控制台输出:


image.png


简单的介绍就到这里吧。


总结



静态代理 和 动态代理  对比 :


静态代理是 一开始咱们编码的时候,已经写死了,哪个代理类对应哪个被代理类。


而动态代理都是 运行时动态即时创建的。


疑问:


那么是不是静态代理就肯定不如动态代理?


那肯定不能这么说,人家静态代理一开始就码好了,运行调用的时候,肯定就快啊。


而动态代理时运行时才去开始,所以自然也会慢。


JDK动态代理 和 CGLIB动态代理:


JDK动态代理,代理的类 必须实现接口,没有实现接口的类 无法使用JDK动态代理。


CGLIB动态代理,代理的类必须能被子类继承使用(方法也得能被重写),所以不能代理声明为final类型的类和方法。


多级代理实现方式:


补充:


如果我们想实现, 在调用下单点餐这个方法时,  不单是 进行日志记录 ,我们还想进行 一个营业判断或者说权限判断。


(JDK动态代理-多层级代理)

这时就会引出一个, 多级代理的概念。


也就是说,


image.png


对应的动态代理切点不止一个:


image.png


我们需要的流程是, 当通过代理方式去调用主业务方法 executeFoodOrder ,先给我进行 日志记录, 再给我进行 营业时间判断(可以类比成一些权限判断、角色判断、身份判断等等),时间判断符合在营业时间时,最后再给我去调用主业务方法 executeFoodOrder 。


实现代码,两个动态代理类


DynamicsLogProxy.java:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
/**
 * @Author : JCccc
 * @CreateTime : 2020/4/21
 * @Description :
 **/
public class DynamicsLogProxy implements InvocationHandler {
    Object obj;
    //绑定委托对象,并返回代理类
    public Object bind(Object obj)
    {
        this.obj = obj;
        //绑定该类实现的所有接口,取得代理类
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("+JDK动态代理LogProxy");
        System.out.println("+下单前我们做点什么.");
        System.out.println("+正在获取目前传入的参数:"+Arrays.toString(args));
        System.out.println("+正在记录.....");
        System.out.println("+准备执行主业务");
        Object res = method.invoke(obj, args);
        System.out.println("+JDK动态代理LogProxy下单后我们做点什么.");
        System.out.println("+可得到业务方法执行后结果"+res.toString());
        System.out.println("+记录.......");
        return res;
    }
}
DynamicsOperateProxy.java:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @Author : JCccc
 * @CreateTime : 2020/4/21
 * @Description :
 **/
public class DynamicsOperateProxy implements InvocationHandler {
    Object obj;
    //绑定委托对象,并返回代理类
    public Object bind(Object obj)
    {
        this.obj = obj;
        //绑定该类实现的所有接口,取得代理类
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----JDK动态代理 OperateProxy 执行主方法前-----");
        Object res =null;
        if (method.getName().equals("executeFoodOrder")){
            System.out.println("-----检测当前时需要下单点餐......");
            System.out.println("-----执行相关判断......");
            System.out.println("-----查看该店是否营业......");
            System.out.println("-----检测XXXXX......");
            System.out.println("-----可以调用主业务");
            // 如果不符合要求, 不执行 method.invoke(obj, args);
            //做拦截处理即可,抛出异常或者重定向等等
            res=   method.invoke(obj, args);
            System.out.println("-----JDK动态代理OperateProxy 执行主方法后----");
        }
        return res;
    }
}


注意此时 ,多级代理的 调用方式:


public static void main(String[] args) {
        OrderService operateProxy= (OrderService) new DynamicsOperateProxy().bind(new OrderServiceImpl());
        OrderService operateAndLogProxy = (OrderService)new DynamicsLogProxy().bind(operateProxy);
        Map<String,Integer> orderMap=new HashMap();
        orderMap.put("白米饭",2);
        orderMap.put("红烧肉",1);
        orderMap.put("水煮鱼",1);
        orderMap.put("番茄炒蛋",1);
        Map result = operateAndLogProxy.executeFoodOrder("JCccc",orderMap);
        System.out.println(result.toString());
    }


细看:


image.png


我们先是让 需要被代理的类 绑定到  DynamicsOperateProxy 上,


然后绑定完创建出来的类,我们继续 绑定到 DynamicsLogProxy 上,然后创建我们最后的多级动态代理类。


看控制台输出:


注意到此时的调用执行顺序,


第一步,进入到了log动态代理,执行 调用主业务方法 前 的 代码;


第二步,即将切回到主业务方法时,发现还有一级代理,operate动态代理,那么进入 operate动态代理 ,执行相关的 执行 调用主业务方法 前 的 代码;


第三步,切入主业务方法,拿到主业务方法的返回结果,回到 operate动态代理,执行 主业务方法调用后的 代码;


第四步,把 ‘拿到主业务方法的返回结果’ 往外面一层传递,也就是传递给 log动态代理,  log动态代理执行 调用主业务方法 后 的 代码。


第五步,最后把最终结果返回到最外面去。


image.png


所以多层级代理使用的时候,需要自己多注意动态代理实现的顺序,记得多测试看看流程。


那么可以看到这种多层级代理的实现方式是使用的JDK动态代理,那么如果我们想用CGLIB动态代理方式去实现这种多层级代理呢?


对于这个我也思索了很久,还未能找到一些实现起来很舒服的方式。


如果是基于Spirng框架或者是Springboot,那么实现多层级代理,直接去使用  注解AOP方式去,多重拦截判断算了。


因为SpringBoot默认的AOP实现就是使用的CGLIB动态代理代理,当然你想切换成JDK动态方式也是可以的,改下配置项就像,但是如果你真的改成JDK动态代理方式,记得,你所编写的需要被代理的类,必须实现接口。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
打赏
0
0
0
0
34
分享
相关文章
JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理: ● JDK动态代理只提供接口的代理,不支持类的代理Proxy.newProxyInstance(类加载器, 代理对象实现的所有接口, 代理执行器) ● CGLIB是通过继承的方式做的动态代理 , 如果某个类被标记为final,那么它是无法使用 CGLIB做动态代理的。Enhancer.create(父类的字节码对象, 代理执行器)
JDK动态代理和CGLIB动态代理
Java动态代理允许在运行时创建代理对象,增强或拦截目标类方法的执行。主要通过两种方式实现:JDK动态代理和CGLIB动态代理。JDK动态代理基于接口,利用`java.lang.reflect.Proxy`类和`InvocationHandler`接口;CGLIB则通过字节码技术生成目标类的子类作为代理,适用于未实现接口的类。两者均用于在方法执行前后添加额外逻辑,如日志记录、权限控制等,广泛应用于AOP框架中。
Java的动态代理
Java动态代理是一种强大的机制,允许在运行时创建接口的代理实例,并拦截方法调用。其核心组件包括`java.lang.reflect.Proxy`和`java.lang.reflect.InvocationHandler`。通过自定义接口、实现接口、编写`InvocationHandler`处理器并生成代理对象,可以灵活地增强方法功能,如日志记录、事务管理等。典型应用场景包括AOP、RPC、延迟加载和Mock测试。与CGLIB相比,JDK动态代理基于接口,性能稍慢但无需第三方库,适用于需要无侵入式增强的场合。
JDK动态代理和CGLIB动态代理
Java动态代理允许在运行时创建代理对象,增强或拦截目标类的方法调用,无需修改原代码。它有两种主要实现方式:JDK动态代理和CGLIB动态代理。 - **JDK动态代理**:通过`java.lang.reflect.Proxy`类和`InvocationHandler`接口实现,适用于实现了接口的类。它在方法调用前后插入额外逻辑,如日志记录、权限控制等。 - **CGLIB动态代理**:基于字节码技术,为未实现接口的类生成子类作为代理,重写父类方法以添加增强逻辑。适用于没有接口的类,但要求目标类不能是`final`类或方法。
探索Java动态代理的奥秘:JDK vs CGLIB
动态代理是一种在 运行时动态生成代理类的技术,无需手动编写代理类代码。它通过拦截目标方法的调用,实现对核心逻辑的 无侵入式增强(如日志、事务、权限控制等)。
61 0
探索Java动态代理的奥秘:JDK vs CGLIB
在Rocky Linux 9上安装JDK并配置环境变量!
本教程介绍在Rocky Linux 9上安装JDK并配置环境变量的完整步骤。首先更新系统,清理旧版本JDK相关包及残留文件,确保环境干净。接着搜索并安装所需版本的JDK(如OpenJDK 17),验证安装是否成功。然后查找JDK安装路径,配置全局环境变量`JAVA_HOME`和`PATH`,最后验证环境变量设置。按照此流程操作,可顺利完成Java开发环境搭建,支持多版本切换(如JDK 8/11/17)。生产环境请谨慎操作,避免影响现有服务。
71 21
|
6月前
|
安装JDK18没有JRE环境的解决办法
安装JDK18没有JRE环境的解决办法
609 61
课时4:JDK的安装与配置
课时4:JDK的安装与配置 摘要: 1. JDK安装:从Oracle官网下载适合操作系统的JDK版本,确保关闭防火墙,选择正确的位数(如64位),并进行一键式安装。 2. JDK配置:将JDK的bin目录路径(如D:\Java\jdk1.8.0_74\bin)添加到系统环境变量PATH中,确保Java开发命令(如javac、java)可用。配置完成后,重启命令行工具验证安装是否成功。 通过以上步骤,确保Java开发环境的正确搭建。
106 0
|
26天前
|
课时5:JDK安装与配置
课时5:JDK安装与配置,主讲人李兴华。课程详细讲解了JDK的安装步骤和环境配置方法,包括选择安装路径、配置系统环境变量(如path),确保javac和java命令在命令行中可用。建议将所有程序安装在D盘,便于管理。安装完成后,需重启命令行以加载新环境配置,确保Java开发环境正常运行。
"解锁Java Web传奇之旅:从JDK1.8到Tomcat,再到MariaDB,一场跨越数据库的冒险安装盛宴,挑战你的技术极限!"
【8月更文挑战第19天】在Linux上搭建Java Web应用环境,需安装JDK 1.8、Tomcat及MariaDB。本指南详述了使用apt-get安装OpenJDK 1.8的方法,并验证其版本。接着下载与解压Tomcat至`/usr/local/`目录,并启动服务。最后,通过apt-get安装MariaDB,设置基本安全配置。完成这些步骤后,即可验证各组件的状态,为部署Java Web应用打下基础。
94 1
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等