- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章spring基础概念AOP与动态代理理解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
1、代理模式 。
代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.
以简单模拟事务的执行过程说明各种代理区别 。
1.1 静态代理 。
由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了.
1
2
3
4
|
public
interface
PersonDao {
void
savePerson();
}
|
1
2
3
4
5
6
7
|
public
class
PersonDaoImpl
implements
PersonDao {
@Override
public
void
savePerson() {
System.out.println(
"save person"
);
}
}
|
1
2
3
4
5
6
7
8
9
10
|
public
class
Transaction {
void
beginTransaction(){
System.out.println(
"begin Transaction"
);
}
void
commit(){
System.out.println(
"commit"
);
}
}
|
接下来编写静态代理类---实现PersonDao接口 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/**
* 静态代理类
* @author qjc
*/
public
class
PersonDaoProxy
implements
PersonDao{
PersonDao personDao;
Transaction transaction;
public
PersonDaoProxy(PersonDao personDao, Transaction transaction) {
this
.personDao = personDao;
this
.transaction = transaction;
}
@Override
public
void
savePerson() {
this
.transaction.beginTransaction();
this
.personDao.savePerson();
this
.transaction.commit();
}
}
|
测试 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/**
* 测试静态代理
* @author qjc
*/
public
class
TestPersonProxy {
@Test
public
void
testSave(){
PersonDao personDao =
new
PersonDaoImpl();
Transaction transaction =
new
Transaction();
PersonDaoProxy proxy =
new
PersonDaoProxy(personDao, transaction);
proxy.savePerson();
}
}
|
总结:
1、静态代理模式并没有做到事务的重用 。
2、假设dao有100个类,100个proxy,接口中有多少方法,在proxy层就得实现多少方法,有多少方法就要开启和提交多少事务 。
3、如果一个proxy实现了多个接口,如果其中的一个接口发生变化(添加了一个方法),那么proxy也要做相应改变 。
1.2 JDK动态代理 。
动态代理类:在程序运行时,运用反射机制动态创建而成.
JDK的动态代理必须具备四个条件:1、目标接口 2、目标类 3、拦截器 4、代理类 。
使用上个例子的PersonDao接口、PersonDaoImpl类及Transaction类 。
编写拦截器 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
import
java.lang.reflect.InvocationHandler;
import
java.lang.reflect.Method;
/**
* 拦截器
* 1、目标类导入进来
* 2、事物导入进来
* 3、invoke完成:开启事务、调用目标对象的方法、事务提交
*
* @author qjc
*/
public
class
Interceptor
implements
InvocationHandler {
private
Object target;
// 目标类
private
Transaction transaction;
public
Interceptor(Object target, Transaction transaction) {
this
.target = target;
this
.transaction = transaction;
}
/**
* @param proxy 目标对象的代理类实例
* @param method 对应于在代理实例上调用接口方法的Method实例
* @param args 传入到代理实例上方法参数值的对象数组
* @return 方法的返回值,没有返回值是null
* @throws Throwable
*/
public
Object invoke(Object proxy, Method method, Object[] args)
throws
Throwable {
String methodName = method.getName();
if
(
"savePerson"
.equals(methodName)
||
"deletePerson"
.equals(methodName)
||
"updatePerson"
.equals(methodName)) {
this
.transaction.beginTransaction();
// 开启事务
method.invoke(target);
// 调用目标方法
this
.transaction.commit();
// 提交事务
}
else
{
method.invoke(target);
}
return
null
;
}
}
|
测试 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/**
* 测试jdk动态代理
* @author qjc
*/
public
class
TestJDKProxy {
@Test
public
void
testSave(){
/**
* 1、创建一个目标对象
* 2、创建一个事务
* 3、创建一个拦截器
* 4、动态产生一个代理对象
*/
Object target =
new
PersonDaoImpl();
Transaction transaction =
new
Transaction();
Interceptor interceptor =
new
Interceptor(target, transaction);
/**
* 参数一:设置代码使用的类加载器,一般采用跟目标类相同的类加载器
* 参数二:设置代理类实现的接口,跟目标类使用相同的接口
* 参数三:设置回调对象,当代理对象的方法被调用时,会调用该参数指定对象的invoke方法
*/
PersonDao personDao = (PersonDao) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
interceptor);
personDao.savePerson();
}
}
|
总结:
1、因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有.
2、生成的代理类的所有的方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体.
3、利用JDKProxy方式必须有接口的存在.
4、invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型.
缺点:
1、在拦截器中除了能调用目标对象的目标方法以外,功能是比较单一的,在这个例子中只能处理事务 。
2、拦截器中的invoke方法的if判断语句在真实的开发环境下是不靠谱的,因为一旦方法很多if语句需要写很多。 。
1.3 CGLIB动态代理 。
使用上个例子的PersonDaoImpl类和Transaction类(不用接口) 。
编写拦截器类 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
import
net.sf.cglib.proxy.Enhancer;
import
net.sf.cglib.proxy.MethodInterceptor;
import
net.sf.cglib.proxy.MethodProxy;
/**
* CGLIB代理 拦截器
* @author qjc
*/
public
class
Interceptor
implements
MethodInterceptor {
private
Object target;
// 代理的目标类
private
Transaction transaction;
public
Interceptor(Object target, Transaction transaction) {
this
.target = target;
this
.transaction = transaction;
}
/**
* 创建目标对象的代理对象
*
* @return
*/
public
Object createProxy() {
// 代码增强
Enhancer enhancer =
new
Enhancer();
// 该类用于生成代理对象
enhancer.setCallback(
this
);
// 参数为拦截器
enhancer.setSuperclass(target.getClass());
// 设置父类
return
enhancer.create();
// 创建代理对象
}
/**
* @param obj 目标对象代理类的实例
* @param method 代理实例上 调用父类方法的Method实例
* @param args 传入到代理实例上方法参数值的对象数组
* @param methodProxy 使用它调用父类的方法
* @return
* @throws Throwable
*/
public
Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy)
throws
Throwable {
this
.transaction.beginTransaction();
method.invoke(target);
this
.transaction.commit();
return
null
;
}
}
|
测试 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* 测试cglib动态代理
* 通过cglib产生的代理对象,代理类是目标类的子类
* @author qjc
*/
public
class
TestCglibProxy {
@Test
public
void
testSave(){
Object target =
new
PersonDaoImpl();
Transaction transaction =
new
Transaction();
Interceptor interceptor =
new
Interceptor(target, transaction);
PersonDaoImpl personDaoImpl = (PersonDaoImpl) interceptor.createProxy();
personDaoImpl.savePerson();
}
}
|
总结:
1、CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口.
2、用CGlib生成代理类是目标类的子类.
3、用CGlib生成 代理类不需要接口 。
4、用CGLib生成的代理类重写了父类的各个方法.
5、拦截器中的intercept方法内容正好就是代理类中的方法体 CGLIB和JDK动态代理区别
JDK
目标类和代理类实现了共同的接口 。
拦截器必须实现InvocationHandler接口,而这个接口中invoke方法体的内容就是代理对象方法体的内容 。
CGLIB
目标类 是代理类的父类 。
拦截器必须实现MethodInterceptor接口,而接口中的intercept方法就是代理类的方法体,使用字节码增强机制创建代理对象的. 。
2、面向切面编程 。
OOP(面向对象编程):封装、继承、多态、抽象 。
封装,对代码进行基本的管理、模块化的管理。每个类可能都有自己的职能,出了问题就是论事找人就行了。从修改角度讲,直接修改代码可能有风险,这不是个长远之计,最自然的是从类型封装变化。但是新的类型和旧的体系之间怎么去融合,所以说需要在类与类之间建立一种血缘关系。那么这就是继承的需求,通过继承就可以发现这些类之间是有关联的,它们之间是有父子关系的。然后在继承基础之上多态起决定性的特征。所以说一般认为面向对象最核心的特征,其实是多态。前面几个都是在做铺垫的。多态才是它最核心的特征。子类中通过重写方法,代表了扩展这个层面的东西,而它能融入老的体系中能够正常工作,这是重用这个层面的东西,新的方法、旧的体系、扩展和重用。 。
AOP(面向切面编程)
面向切面编程,是一种通过预编译方式运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. 。
OOP与AOP区别
OOP:针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清楚的逻辑单元划分.
AOP:针对业务处理过程中的横切逻辑 进行提取,它所面对的是处理过程中的某个步骤或者阶段,以获得逻辑过程中各部分之间低耦合的隔离效果。这两种设计思想在目标上有着本质的差异。AOP做到了代码块的重用。 。
spring AOP代理机制:
1、若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理.
优点:因为有接口,所以使系统更加松耦合 。
缺点:为每一个目标类创建接口 。
2、若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类.
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在.
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好.
使用第一个例子的 PersonDao接口、PersonDaoImpl类和Transaction类 。
编写spring配置 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<bean id=
"personDao"
class
=
"cn.qjc.aop.xml.PersonDaoImpl"
></bean>
<bean id=
"transaction"
class
=
"cn.qjc.aop.xml.Transaction"
></bean>
<aop:config>
<!-- 切入点表达式 确定目标类 -->
<aop:pointcut expression=
"execution(* cn.qjc.aop.xml.PersonDaoImpl.*(..))"
id=
"perform"
/>
<!-- ref指向对象就是切面 -->
<aop:aspect ref=
"transaction"
>
<aop:before method=
"beginTransaction"
pointcut-ref=
"perform"
/>
<aop:after-returning method=
"commit"
pointcut-ref=
"perform"
/>
</aop:aspect>
</aop:config>
</beans>
|
测试 。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/**
* 测试spring动态代理
* @author qjc
*/
public
class
TransactionTest {
@Test
public
void
testSave(){
ApplicationContext context =
new
ClassPathXmlApplicationContext(
"cn/qjc/aop/xml/applicationContext.xml"
);
PersonDao personDao = (PersonDao) context.getBean(
"personDao"
);
personDao.savePerson();
}
}
|
spring AOP原理 。
1、当spring容器启动的时候,加载两个bean,对像个bean进行实例化 2、当spring容器对配置文件解析到<aop:config>的时候,把切入点表达式解析出来,按照切入点表达式匹配spring容器内容的bean 3、如果匹配成功,则为该bean创建代理对象 4、当客户端利用context.getBean获取一个对象时,如果该对象有代理对象,则返回代理对象,如果没有代理对象,则返回对象本身 。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
最后此篇关于spring基础概念AOP与动态代理理解的文章就讲到这里了,如果你想了解更多关于spring基础概念AOP与动态代理理解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 10年前关闭。 Improve this qu
我正在开发一个 Android 应用程序。在此应用程序中, Logo 栏显示在所有页面( Activity )上,或者我们可以说它在所有页面上都有标题。这个 Logo 栏有几个图标,如主页、登录、通知
我正在使用 hadoop 使用开源接口(interface) HVPI 处理视频。然而,inputsplit 的实现,更准确地说是在 isSplitableobContext (context, Pa
1. 是什么? MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System
有没有办法使用 c++20s 的概念来检查一个值是否满足某些要求? 假设我正在编写某种使用分页的容器,并且我想让页面大小成为模板参数。 template class container; 我可以使用带
如何在 ArrayList 中循环遍历 ArrayList? 例如,如果我有一个名为 Plants of Plant 对象的 ArrayList。每个 Plant 对象内部都有一个随机数量的花名。我如
如何在UML类图中绘制C++概念? 具体来说,我有以下代码: template concept Printable = requires(T a, std::ostream &where) {
我有兴趣制作一个网站,在访问者访问时闪现整个网络历史记录。我计划使用 JavaScript 来获取每个观看者计算机上的历史记录,并根据他们拥有的内容以不同的速度对其进行动画处理。我的想法是使用 his
有一个模板定义,例如: template void foo( void ) { /* ... */ } 如何定义一个概念,以便N必须为非零正值(N> = 1)? 就像是: template con
封装是信息隐藏还是导致信息隐藏? 正如我们所说,封装将数据和函数绑定(bind)在单个实体中,因此它为我们提供了对数据流的控制,并且我们只能通过一些定义良好的函数来访问实体的数据。因此,当我们说封装导
下面有一个简单的代码片段,它使用以下方式进行编译: g++-9 -std=c++2a -fconcepts 这是试图定义一个需要存在函数的概念。我希望输出是"is",但事实并非如此……知道为什么吗?谢
我有一个普通二元运算符的概念 template concept is_binary_operation = requires (const T& t1, const T& t2) // e.g
我正在c++ 20中实现具有启发式功能的搜索算法。 我试图用类似这样的概念来约束我的算法可以使用的功能: template concept Heuristic = requires(SelfType
我需要了解 SAS 如何读取/执行数据步骤。当我查找有关 SAS 如何读取数据步骤的信息时,我似乎只找到有关它如何读取以进行合并的信息,我不了解与常规数据步骤相关的信息。比方说,我有这行代码: dat
最近我看到一个关于“框架”的问题,如果“框架”有不同的类型或概念。那么,存在不同“类型”的“框架”吗? 例如:NodeJS 是一种“类型”(概念),而 Hibernate ORM 是另一种“类型”(概
如何使用任何技术禁用或清除客户端浏览器 Cookie 我认为使用 javascript 可以用于任何技术 最佳答案 var cookies = document.cookie.split(";");
我正在使用 target = "_blank" 单击链接时生成新选项卡。但是,浏览器会将焦点移至该选项卡。 有没有办法让焦点保持在当前标签页上? 回答摘要 基本上,只需发送一个模拟控件点击的当前事件。
我正在尝试在我的 android/firebase(cloud firestore) 应用程序上添加一项需要其他用户批准/拒绝的功能。例如,当 Air&BnB 上的用户想要预订一个地方时,所有者必须批
这个问题在这里已经有了答案: mysql_fetch_array()/mysql_fetch_assoc()/mysql_fetch_row()/mysql_num_rows etc... expec
public class MyClass { public static void main(String[] args) { System.out.println("Hell
我是一名优秀的程序员,十分优秀!