JAVA八股与代码实践----JDK代理和CGLIB代理的区别

当spring发现该代理的类实现了接口会使用JDK代理,如果该类没有实现接口,会使用CGLIB代理

如果在springboot中要强制使用CGLIB代理,需要加上

@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用 CGLIB

@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用 CGLIB
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

动态代理的典型应用就是AOP

1、动态代理代码示例(JDK)(非AOP)

1.1、定义bean和代理逻辑

// 目标类(实际的业务逻辑)
public class UserService {
    public void addUser(String username) {
        System.out.println("User " + username + " added.");
    }

    public void deleteUser(String username) {
        System.out.println("User " + username + " deleted.");
    }
}

// 自定义 InvocationHandler 实现
public class LoggingInvocationHandler implements InvocationHandler {
    private Object target; // 被代理对象

    public LoggingInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置逻辑
        System.out.println("[LOG] Method " + method.getName() + " is called with args: " + java.util.Arrays.toString(args));

        // 调用目标方法
        Object result = method.invoke(target, args);

        // 后置逻辑
        System.out.println("[LOG] Method " + method.getName() + " execution completed.");

        return result;
    }
}




1.2、生成动态代理bean

public class ProxyExample {
    public static void main(String[] args) {
        // 创建目标对象(真实的 Bean)
        UserService userService = new UserService();

        // 创建代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
            userService.getClass().getClassLoader(), // 类加载器
            userService.getClass().getInterfaces(),  // 目标类实现的接口
            new LoggingInvocationHandler(userService) // 代理逻辑
        );

        // 调用代理方法
        proxy.addUser("Alice");
        proxy.deleteUser("Bob");
    }
}

结果:

[LOG] Method addUser is called with args: [Alice]
User Alice added.
[LOG] Method addUser execution completed.
[LOG] Method deleteUser is called with args: [Bob]
User Bob deleted.
[LOG] Method deleteUser execution completed.

2、动态代理代码示例(JDK)(AOP)

@Service // 标记为 Spring 容器管理的 Bean
public class UserService {

    public void addUser(String username) {
        System.out.println("User " + username + " added.");
    }

    public void deleteUser(String username) {
        System.out.println("User " + username + " deleted.");
    }
}

@Aspect
@Component // 标记为 Spring 管理的 Bean
public class LoggingAspect {

    @Before("execution(* com.example.service.UserService.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("[LOG] Before method: " + joinPoint.getSignature().getName());
    }

    @After("execution(* com.example.service.UserService.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("[LOG] After method: " + joinPoint.getSignature().getName());
    }
}
### Java基础面试题及答案 #### 1. **Java程序的入口点是什么?** Java程序的入口点是 `main()` 方法所在的类,称为主类。在 Java 应用程序中,主类是指包含 `main()` 方法的类;而在 Java 小程序中,主类是一个继承自系统类 `JApplet` 或 `Applet` 的子类[^1]。 ```java public class MainClass { public static void main(String[] args) { System.out.println("This is the entry point of a Java application."); } } ``` --- #### 2. **try-catch-finally 块的作用分别是什么?** - `try` 块用于包含可能抛出异常的代码- `catch` 块用于捕获并处理由 `try` 块中抛出的异常。可以定义多个 `catch` 块来处理不同类型异常。 - `finally` 块中的代码无论如何都会被执行,常用于释放资源(如关闭文件、数据库连接等)。即使发生未被捕获的异常或提前返回,`finally` 中的内容也会运行[^2]。 示例代码如下: ```java try { int result = 1 / 0; // 可能会抛出 ArithmeticException } catch (ArithmeticException e) { System.out.println("Error: " + e.getMessage()); } finally { System.out.println("Finally block is executed"); } ``` --- #### 3. **什么是反射机制?它的应用场景有哪些?** 反射机制允许程序在运行时获取类的信息以及操作对象的方法、字段构造器。其主要应用包括但不限于以下场景: - 动态创建对象实例。 - 调用私有方法或访问私有属性。 - 实现框架功能(如 Spring Hibernate 使用反射完成依赖注入 ORM 映射)。 需要注意的是,虽然反射提供了灵活性,但它也带来了性能开销安全风险。 --- #### 4. **为什么同一个 `.class` 文件通过不同的类加载器加载会被视为不同的类?** 这是因为 JVM 判断两个类是否相同不仅基于它们的名字,还取决于加载该类的类加载器。如果相同的 `.class` 文件被不同的类加载器加载,则这些类被认为是独立的不同类。这种设计的主要目的是为了增强安全性(防止恶意代码替换核心类)避免重复加载同一份字节码[^3]。 --- #### 5. **OOP 是什么?它 AOP 的区别在哪里?** 面向对象编程(Object-Oriented Programming, OOP)是一种以对象为核心的设计范式,强调封装、继承多态三大特性。而面向切面编程(Aspect-Oriented Programming, AOP)则关注于分离横切逻辑(如日志记录、事务管理),从而提高模块化程度。Spring AOP 主要利用 JDK 动态代理或者 CGLIB 来实现,在不需要接口支持的情况下也能完成动态代理的功能[^4]。 --- #### 6. **String 类为何不可变?** 字符串不可变得益于以下几个原因: - 提升线程安全性:由于共享数据不会改变,因此无需额外同步控制。 - 缓存哈希值优化:一旦计算过某个字符串的哈希值就可以永久保存下来供后续调用使用。 - 减少内存消耗:当存在大量相等字符串时可以通过重用来节省空间。 此外,限制用户修改底层结构有助于保护内部状态的一致性完整性[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值