- 浏览: 520184 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (422)
- 重要 (12)
- BUG解决备忘录 (32)
- 环境搭建 (17)
- 开源组件 (4)
- 数据库 (16)
- 设计模式 (4)
- 测试 (3)
- javascript (5)
- Android (14)
- jdk相关 (9)
- struts2 (10)
- freemark (3)
- 自定义扩展及工具类 (5)
- jdk5新特性及java基础 (13)
- ssh及其他框架 (15)
- linux (32)
- tcp-ip http协议 (8)
- 服务器集群与负载均衡 (34)
- 项目管理相关 (11)
- 实用小技术 (10)
- 架构相关 (14)
- firefox组件 (11)
- spider (6)
- 产品设计 (11)
- PHP (1)
- ws (4)
- lucene (10)
- 其他 (2)
- BI (1)
- NoSQL (3)
- gzip (1)
- ext (4)
- db (6)
- socket (1)
- 源码阅读 (2)
- NIO (2)
- 图片处理 (1)
- java 环境 (2)
- 项目管理 (4)
- 从程序员到项目经理(一):没有捷径 (1)
- bug (1)
- JAVA BASE (8)
- 技术原理 (0)
- 新框架新技术 (1)
- 量化与python (1)
- 系统编程 (0)
- C语言 (0)
- 汇编 (0)
- 算法 (0)
最新评论
-
hyspace:
别逗了,最后一个算法根本不是最优的,sort(function ...
数组去重——一道前端校招试题 -
washingtin:
楼主能把策略和路由的类代码贴出来吗
Spring + iBatis 的多库横向切分简易解决思路 -
sdyjmc:
初略看了一下,没有闹明白啊,均衡负载使用Nginx,sessi ...
J2EE集群原理 I -
shandeai520:
谢谢大神!请教大神一个问题:假如我有三台服务器,连接池的上限是 ...
集群和数据库负载均衡的研究 -
hekuilove:
给lz推荐一下apache commonsStringUtil ...
request 获取 ip
CGlib概述:
cglib(Code Generation Library
)是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
cglib封装了asm,可以在运行期动态生成新的class。
cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。
CGlib应用:
以一个实例在简单介绍下cglib的应用。
我们模拟一个虚拟的场景,关于信息的管理。
1)原始需求是任何人可以操作信息的create,update,delete,query操作。
InfoManager.java
--封装对信息的操作
// 模拟查询操作
public void query() {
System.out.println( " query " );
}
// 模拟创建操作
public void create() {
System.out.println( " create " );
}
// 模拟更新操作
public void update() {
System.out.println( " update " );
}
// 模拟删除操作
public void delete() {
System.out.println( " delete " );
}
}
InfoManagerFactory.java --工厂类
private static InfoManager manger = new InfoManager();
/**
* 创建原始的InfoManager
*
* @return
*/
public static InfoManager getInstance() {
return manger;
}
}
client.java --供客户端调用
public static void main(String[] args) {
Client c = new Client();
c.anyonecanManager();
}
/**
* 模拟:没有任何权限要求,任何人都可以操作
*/
public void anyonecanManager() {
System.out.println( " any one can do manager " );
InfoManager manager = InfoManagerFactory.getInstance();
doCRUD(manager);
separatorLine();
}
/**
* 对Info做增加/更新/删除/查询操作
*
* @param manager
*/
private void doCRUD(InfoManager manager) {
manager.create();
manager.update();
manager.delete();
manager.query();
}
/**
* 加一个分隔行,用于区分
*/
private void separatorLine() {
System.out.println( " ################################ " );
}
}
至此,没有涉及到cglib的内容,因为需求太简单了,但是接下来,需求发生了改变,要求:
2)只有一个叫“maurice”的用户登录,才允许对信息进行create,update,delete,query的操作。
怎么办?难道在每个方法前,都加上一个权限判断吗?这样重复逻辑太多了,于是乎想到了Proxy(代理模式),但是原先的InfoManager也没有实现接口,不能采用jdk的proxy。那么cglib在这边就要隆重登场。
一旦使用cgblig,只需要添加一个MethodInterceptor的类以及修改factory代码就可以实现这个需求。
AuthProxy.java
--权限校验代理类
private String name; // 会员登录名
public AuthProxy(String name) {
this .name = name;
}
/**
* 权限校验,如果会员名为:maurice,则有权限做操作,否则提示没有权限
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if ( ! " maurice " .equals( this .name)) {
System.out.println( " AuthProxy:you have no permits to do manager! " );
return null ;
}
return proxy.invokeSuper(obj, args);
}
public String getName() {
return name;
}
public void setName(String name) {
this .name = name;
}
}
InfoManagerFactory.java --代码变动如下:
/**
* 创建带有权限检验的InfoManager
*
* @param auth
* @return
*/
public static InfoManager getAuthInstance(AuthProxy auth) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(InfoManager. class );
enhancer.setCallback(auth);
return (InfoManager) enhancer.create();
}
}
client.java --代码修改如下
public static void main(String[] args) {
Client c = new Client();
c.haveNoAuthManager();
c.haveAuthManager();
}
/**
* 模拟:登录会员没有权限
*/
public void haveNoAuthManager() {
System.out.println( " the loginer's name is not maurice,so have no permits do manager " );
InfoManager noAuthManager = InfoManagerFactory.getAuthInstance( new AuthProxy( " maurice1 " ));
doCRUD(noAuthManager);
separatorLine();
}
/**
* 模拟:登录会员有权限
*/
public void haveAuthManager() {
System.out.println( " the loginer's name is maurice,so have permits do manager " );
InfoManager authManager = InfoManagerFactory.getAuthInstance( new AuthProxy( " maurice " ));
doCRUD(authManager);
separatorLine();
}
/**
* 对Info做增加/更新/删除/查询操作
*
* @param manager
*/
private void doCRUD(InfoManager manager) {
manager.create();
manager.update();
manager.delete();
manager.query();
}
/**
* 加一个分隔行,用于区分
*/
private void separatorLine() {
System.out.println( " ################################ " );
}
}
执行下代码,发现这时client端中已经加上了权限校验。
同样是InfoManager,为什么这时能多了权限的判断呢?Factory中enhancer.create()返回的到底是什么对象呢?这个疑问将在第三部分CGlib中解释。
这边的代码,其实是介绍了cglib中的enhancer功能.
到这里,参照上面的代码,就可以使用cglib带来的aop功能了。但是为了更多介绍下cglib的功能,模拟需求再次发生变化:
3)由于query功能用户maurice才能使用,招来其他用户的强烈的抱怨,所以权限再次变更,只有create,update,delete,才需要权限保护,query任何人都可以使用。
怎
么办?采用AuthProxy,使得InfoManager中的所有方法都被代理,加上了权限的判断。当然,最容易想到的办法,就是在AuthProxy
的intercept的方法中再做下判断,如果代理的method是query,不需要权限验证。这么做,可以,但是一旦逻辑比较复杂的时
候,intercept这个方法要做的事情会很多,逻辑会异常的复杂。
幸好,cglib还提供了CallbackFilter。使用CallbackFilter,可以明确表明,被代理的类(InfoManager)中不同的方法,被哪个拦截器(interceptor)拦截。
AuthProxyFilter.java
private static final int AUTH_NEED = 0 ;
private static final int AUTH_NOT_NEED = 1 ;
/**
* <pre>
* 选择使用的proxy
* 如果调用query函数,则使用第二个proxy
* 否则,使用第一个proxy
* </pre>
*/
@Override
public int accept(Method method) {
if ( " query " .equals(method.getName())) {
return AUTH_NOT_NEED;
}
return AUTH_NEED;
}
}
这段代码什么意思?其中的accept方法的意思是说,如果代理的方法是query(),那么使用第二个拦截器去拦截,如果代理的方法不是
query(),那么使用第一个拦截器去拦截。所以我们只要再写一个拦截器,不做权限校验就行了。(其实,cglib中的NoOp.INSTANCE就是
一个空的拦截器,只要配置上这个就可以了。)
InfoManagerFactory.java
--代码修改如下:(配置不同的拦截器和filter)
/**
* 创建不同权限要求的InfoManager
*
* @param auth
* @return
*/
public static InfoManager getSelectivityAuthInstance(AuthProxy auth) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(InfoManager. class );
enhancer.setCallbacks( new Callback[] { auth, NoOp.INSTANCE });
enhancer.setCallbackFilter( new AuthProxyFilter());
return (InfoManager) enhancer.create();
}
}
记住:setCallbacks中的拦截器(interceptor)的顺序,一定要和CallbackFilter里面指定的顺序一致!!切忌。
Client.java
public static void main(String[] args) {
Client c = new Client();
c.selectivityAuthManager();
}
/**
* 模拟:没有权限的会员,可以作查询操作
*/
public void selectivityAuthManager() {
System.out.println( " the loginer's name is not maurice,so have no permits do manager except do query operator " );
InfoManager authManager = InfoManagerFactory.getSelectivityAuthInstance( new AuthProxy( " maurice1 " ));
doCRUD(authManager);
separatorLine();
}
/**
* 对Info做增加/更新/删除/查询操作
*
* @param manager
*/
private void doCRUD(InfoManager manager) {
manager.create();
manager.update();
manager.delete();
manager.query();
}
/**
* 加一个分隔行,用于区分
*/
private void separatorLine() {
System.out.println( " ################################ " );
}
}
此时,对于query的权限校验已经被去掉了。
通过一个模拟需求,简单介绍了cglib aop功能的使用。
CGlib应用非常广,在spring,hibernate等框架中,被大量的使用。
CGlib原理:
cglib神奇吗?其实一旦了解cglib enhancer的原理,一切就真相大白了。
刚才在第二部分中,有个疑问:enhancer.create()到底返回了什么对象?
其实在刚才的例子中,cglib在代码运行期,动态生成了InfoManager的子类,并且根据CallbackFilter的accept方法,覆写了InfoManager中的所有方法--去执行相应的MethodInterceptor的intercept方法。
有兴趣的朋友可以看看我反编译的InfoManager的子类,就可以很明白知道具体的实现了。(需要有耐心才可以)
InfoManager$$EnhancerByCGLIB$$de624598.jad
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3)
// Source File Name: <generated>
package cn.eulic.codelab.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy. * ;
// Referenced classes of package cn.eulic.codelab.cglib:
// InfoManager
public class CGLIB.BIND_CALLBACKS extends InfoManager
implements Factory
{
static void CGLIB$STATICHOOK1()
{
Class class1;
ClassLoader classloader;
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
classloader = (class1 = Class.forName( " cn.eulic.codelab.cglib.InfoManager$$EnhancerByCGLIB$$de624598 " )).getClassLoader();
classloader;
CGLIB$emptyArgs = new Object[ 0 ];
CGLIB$delete$ 0 $Proxy = MethodProxy.create(classloader, (CGLIB$delete$ 0 $Method = Class.forName( " cn.eulic.codelab.cglib.InfoManager " ).getDeclaredMethod( " delete " , new Class[ 0 ])).getDeclaringClass(), class1, " ()V " , " delete " , " CGLIB$delete$0 " );
CGLIB$create$ 1 $Proxy = MethodProxy.create(classloader, (CGLIB$create$ 1 $Method = Class.forName( " cn.eulic.codelab.cglib.InfoManager " ).getDeclaredMethod( " create " , new Class[ 0 ])).getDeclaringClass(), class1, " ()V " , " create " , " CGLIB$create$1 " );
CGLIB$query$ 2 $Proxy = MethodProxy.create(classloader, (CGLIB$query$ 2 $Method = Class.forName( " cn.eulic.codelab.cglib.InfoManager " ).getDeclaredMethod( " query " , new Class[ 0 ])).getDeclaringClass(), class1, " ()V " , " query " , " CGLIB$query$2 " );
CGLIB$update$ 3 $Proxy = MethodProxy.create(classloader, (CGLIB$update$ 3 $Method = Class.forName( " cn.eulic.codelab.cglib.InfoManager " ).getDeclaredMethod( " update " , new Class[ 0 ])).getDeclaringClass(), class1, " ()V " , " update " , " CGLIB$update$3 " );
CGLIB$finalize$ 4 $Proxy = MethodProxy.create(classloader, (CGLIB$finalize$ 4 $Method = Class.forName( " java.lang.Object " ).getDeclaredMethod( " finalize " , new Class[ 0 ])).getDeclaringClass(), class1, " ()V " , " finalize " , " CGLIB$finalize$4 " );
CGLIB$hashCode$ 5 $Proxy = MethodProxy.create(classloader, (CGLIB$hashCode$ 5 $Method = Class.forName( " java.lang.Object " ).getDeclaredMethod( " hashCode " , new Class[ 0 ])).getDeclaringClass(), class1, " ()I " , " hashCode " , " CGLIB$hashCode$5 " );
CGLIB$clone$ 6 $Proxy = MethodProxy.create(classloader, (CGLIB$clone$ 6 $Method = Class.forName( " java.lang.Object " ).getDeclaredMethod( " clone " , new Class[ 0 ])).getDeclaringClass(), class1, " ()Ljava/lang/Object; " , " clone " , " CGLIB$clone$6 " );
CGLIB$equals$ 7 $Proxy = MethodProxy.create(classloader, (CGLIB$equals$ 7 $Method = Class.forName( " java.lang.Object " ).getDeclaredMethod( " equals " , new Class[] {
Class.forName( " java.lang.Object " )
})).getDeclaringClass(), class1, " (Ljava/lang/Object;)Z " , " equals " , " CGLIB$equals$7 " );
CGLIB$toString$ 8 $Proxy = MethodProxy.create(classloader, (CGLIB$toString$ 8 $Method = Class.forName( " java.lang.Object " ).getDeclaredMethod( " toString " , new Class[ 0 ])).getDeclaringClass(), class1, " ()Ljava/lang/String; " , " toString " , " CGLIB$toString$8 " );
return ;
}
final void CGLIB$delete$ 0 ()
{
super .delete();
}
public final void delete()
{
CGLIB$CALLBACK_0;
if (CGLIB$CALLBACK_0 != null ) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS( this );
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37 ;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this ;
CGLIB$delete$ 0 $Method;
CGLIB$emptyArgs;
CGLIB$delete$ 0 $Proxy;
intercept();
return ;
super .delete();
return ;
}
final void CGLIB$create$ 1 ()
{
super .create();
}
public final void create()
{
CGLIB$CALLBACK_0;
if (CGLIB$CALLBACK_0 != null ) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS( this );
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37 ;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this ;
CGLIB$create$ 1 $Method;
CGLIB$emptyArgs;
CGLIB$create$ 1 $Proxy;
intercept();
return ;
super .create();
return ;
}
final void CGLIB$query$ 2 ()
{
super .query();
}
public final void query()
{
CGLIB$CALLBACK_0;
if (CGLIB$CALLBACK_0 != null ) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS( this );
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37 ;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this ;
CGLIB$query$ 2 $Method;
CGLIB$emptyArgs;
CGLIB$query$ 2 $Proxy;
intercept();
return ;
super .query();
return ;
}
final void CGLIB$update$ 3 ()
{
super .update();
}
public final void update()
{
CGLIB$CALLBACK_0;
if (CGLIB$CALLBACK_0 != null ) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS( this );
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37 ;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this ;
CGLIB$update$ 3 $Method;
CGLIB$emptyArgs;
CGLIB$update$ 3 $Proxy;
intercept();
return ;
super .update();
return ;
}
final void CGLIB$finalize$ 4 ()
throws Throwable
{
super .finalize();
}
protected final void finalize()
throws Throwable
{
CGLIB$CALLBACK_0;
if (CGLIB$CALLBACK_0 != null ) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS( this );
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 37 ;
goto _L3 _L4
_L3:
break MISSING_BLOCK_LABEL_21;
_L4:
break MISSING_BLOCK_LABEL_37;
this ;
CGLIB$finalize$ 4 $Method;
CGLIB$emptyArgs;
CGLIB$finalize$ 4 $Proxy;
intercept();
return ;
super .finalize();
return ;
}
final int CGLIB$hashCode$ 5 ()
{
return super .hashCode();
}
public final int hashCode()
{
CGLIB$CALLBACK_0;
if (CGLIB$CALLBACK_0 != null ) goto _L2; else goto _L1
_L1:
JVM INSTR pop ;
CGLIB$BIND_CALLBACKS( this );
CGLIB$CALLBACK_0;
_L2:
JVM INSTR dup ;
JVM INSTR ifnull 52 ;
goto _L3 _L4
_L3:
this ;
CGLIB$hashCode$ 5 $Method;
CGLIB$emptyArgs;
CGLIB$hashCode$ 5 $Proxy;
intercept();
JVM INSTR dup ;
JVM INSTR ifnonnull 45 ;
goto _L
发表评论
-
财务风控的几点建议
2018-12-25 15:16 0给出了点意见总结如下1 依据申报三表数据, ... -
房价的几点思考
2018-09-25 10:08 353房价的几点思考 1 供需决定价格 供给:国家土地限量 ... -
专题技术学习网站
2013-04-27 13:57 864#虚拟机 http://hllvm.group.itey ... -
注解apt工具示例程序
2013-03-12 11:45 926今天按照《Thinking in Java》中使用apt处理 ... -
创业团队产品诞生记(三):产品设计
2011-01-03 23:26 12462007年8月,创业团队忙于奥运志愿者报名项目,忙完一个阶段后 ... -
创业团队产品诞生记(二):ZCMS需求分析
2011-01-03 23:25 1594确定做网站内容管理系 ... -
创业团队产品诞生记
2011-01-03 23:25 8142006年年底,创业伊始,来一个项目做一个项目,每天都是做项 ... -
高手blog地址收集
2010-12-23 14:50 999觉先 http://www.cnblogs.com/f ... -
HOSTS设置
2010-12-07 14:21 1358外网可以顺利访问域名 但是内网不能访问只能输入IP访问 上 ... -
阻抗不匹配
2010-12-01 21:11 911持久化存储数据所采用的数据模型(无论是文件系统还是数据库管理系 ... -
SOA 简介
2010-12-01 00:36 1116SOA并不是一个新事物,IT组织已经成功建立并实施SOA应用软 ... -
解析:2010年云计算落地从私有云开始
2010-12-01 00:30 8393月15日 云计算是一种 ...
相关推荐
动态代理主要分为两种技术:JDK动态代理和CGLIB动态代理。 ### JDK动态代理 JDK动态代理是Java内置的一种机制,依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。以下是JDK动态...
1. **功能概述** ASM是一个Java字节码操纵和分析框架,它可以直接生成和加载Java类。ASM提供了低级别的API,可以精确地控制类或接口的生成,使得开发者能够构建自己的编译器、反编译器或者代码分析工具。 2. **...
2. CGLib概述 CGLib是一个强大的、高性能的代码生成库,它可以在运行期扩展Java类与实现Java接口。它广泛用于许多AOP(面向切面编程)框架,如Spring AOP和dynaop,作为JDK动态代理的替代品,当目标类不支持接口时,...
一、CGlib概述 CGlib是一个针对Java的代码生成库,它通过代理技术在运行时动态生成新的子类来扩展已有类的功能,这使得我们可以在不修改源代码的情况下对目标类进行功能增强。CGlib的核心组件是Enhancer,它负责...
一、CGlib概述 CGlib(Code Generation Library)是一个强大的代码生成库,最初由Eugene Kuleshov开发,现已成为Apache软件基金会的一个项目。CGlib的主要功能是动态生成子类,通过这种方式,它可以为任何未实现...
#### 一、代理模式概述 代理模式是一种结构型设计模式,其中代理类含有一个对真实主题对象的引用,这样代理对象就可以执行一些预备或清理工作,并将真正的调用传递给真实主题对象。 在Java中,代理模式的应用非常...
**Spring框架概述** Spring是一个开源的Java/Java EE全功能栈的应用开发框架。它的核心特性包括依赖注入(DI)和面向切面编程(AOP),这使得开发者可以编写松耦合、可测试的代码。Spring还提供了大量的其他功能,如...
项目概述 该项目主要用于测试和验证cglib库的动态代理功能。cglib是一个强大的Java库,用于生成和操作字节码,特别是在需要动态代理和AOP(面向切面编程)的场景中非常有用。通过该项目,开发者可以深入理解cglib...
**知识点概述:** - **自我介绍**:在技术面试中,自我介绍不仅是为了展示个人背景,更是为了体现自己的专业技能和个人特质。应聘者应该简明扼要地介绍自己的教育背景、工作经验以及与职位相关的技能。 - **解决问题...
以下是一个简单的步骤概述: 1. **定义目标类(Target Class)**:首先,我们需要一个业务逻辑类,例如`MyService`,它包含我们想要增强的方法。 ```java public class MyService { public void doSomething() { ...
**知识点概述:** 在Java Spring框架的学习过程中,SSH(Struts + Spring + Hibernate)的整合是一个重要的环节。本课程主要介绍如何使用注解的方式来进行SSH整合,这种方式可以减少XML配置的复杂度,并且更符合...
标题中的“业余框架整合-SSHD-(1)-整体概述”表明了这个压缩包可能包含的是一个关于SSH(Spring、Struts、Hibernate)三大框架整合的教程或项目实践,重点是第一部分的整体概述。SSH框架是Java开发中常用的一个Web...
**Spring AOP 概述** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要组成部分,它提供了在不修改源代码的情况下,对应用程序进行功能增强的能力。AOP的核心概念是切面(Aspect...
一、AOP概述 AOP的核心理念在于将横切关注点(如日志、安全检查)与业务逻辑分离,提高代码的可读性和可维护性。在Spring AOP中,这种分离是通过创建切面(Aspect)和定义通知(Advice)来实现的。切面是封装了特定...
1. Spring 框架概述: Spring框架的核心特性在于IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入),它通过管理对象的生命周期和依赖关系,降低了组件之间的耦合度。此外,Spring还...
#### 一、JAVA反射机制概述 JAVA的反射机制是一种强大的功能,允许程序在运行时获取自身的结构信息并能够直接操作这些内部结构。这种能力通常被称为运行时类型信息(RunTime Type Information, RTTI)。通过反射...
### Spring框架概述与核心原理 #### 一、Spring框架简介 Spring框架是一个广泛使用的开源Java平台,用于构建高质量的企业级应用程序。它最初由Rod Johnson在2004年创建,旨在简化企业级Java应用程序的开发过程。...
#### 概述 在软件开发领域,面向切面编程(Aspect Oriented Programming, AOP)是一种编程范式,旨在提高程序模块化程度,通过分离关注点(Separation of Concerns, SoC)的方式将横切关注点(Cross-cutting ...
### 课程内容概述 #### 1. Spring容器 - **容器接口**:介绍Spring容器的基本概念以及核心接口。 - **容器实现**:分析Spring提供的不同容器实现方式。 - **Bean的生命周期**:探讨Bean在Spring容器中的整个生命...