版权声明:Arno https://blog.csdn.net/yu342107056/article/details/85793851
面向对象的设计原则:
开闭原则:对于修改来说是关闭,对于扩展来说是开放的
单一职责原则:
一个项目的功能单一
一个模块的功能单一
一个接口/类的功能单一
一个方法的功能单一
一个变量的功能单一
代理设计模式:
提出一个问题:
有一套原有的业务模型 符合单一职责
有一套新的功能 符合单一职责
要把新的功能添加到原有业务模型中,填在原有业务模型的前或后,不是添在中间
解决方案:
方案一:
在原有业务方法的第一行填写新功能代码
在原有业务方法的最后一行填写新功能代码
违反开闭原则,和单一职责
是能完成添加新功能的需求,只是设计的不太好
方案二:
代理设计模式实现
遵守开闭原则,和单一职责
代理设计模式的分类:
静态代理
动态代理
jdk的动态代理
cglib的动态代理
静态代理:
原有的业务模型
UserDao.java UserDaoImpl.java
UserService.java UserServiceImpl.java
新功能:事务管理
TransactionManager.java
目标:要把新的功能(事务管理)切入到指定业务方法的前或后
在业务方法的前添加事务的开启
在业务方法的后添加事务的,没错误就提交,有错误就回滚
原有业务有了
新业务也有了
新建一个类,在新建类中把老业务和新业务耦合在一起
TransactionManager.java
/**
* 此类是一个新功能类,用于给原有业务添加事务处理的功能
* 符合单一职责原则,此类只做事务管理
* @author Administrator
*
*/
public class TransactionManager {
/**
* 事务的开启
*/
public void begin(){
System.out.println("事务开启");
}
/**
* 事务提交
*/
public void commit(){
System.out.println("事务提交");
}
/**
* 事务的回滚
*/
public void rollback(){
System.out.println("事务回滚");
}
}
StaticProxy.java
public class StaticProxy implements UserService {
//老业务
private UserService userService;
//新业务
private TransactionManager transactionManager;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setTransactionManager(TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Override
public boolean addUser(User user) {
try{
transactionManager.begin();
userService.addUser(user);
transactionManager.commit();
}catch(Exception e){
transactionManager.rollback();
e.printStackTrace();
}
return false;
}
@Override
public boolean updateUser(User user) {
try{
transactionManager.begin();
userService.updateUser(user);
transactionManager.commit();
}catch(Exception e){
transactionManager.rollback();
e.printStackTrace();
}
return false;
}
}
总结静态代理:
1.原有的老业务,没有被破坏,符合单一职责
2.新的业务,符合单一职责
3.把新的业务要添加到老业务中
a.新建一个老业务和新业务的耦合类,此耦合类就叫做静态代理类
b.静态代理类要求必须实现自业务的接口,因为静态代理类的功能不能少于原有业务功能
c.静态代理类不满足单一职责原则,因为老功能和新功能耦合在一起
d.每一个套业务,都会对应一个静态代理类
比如:UserService UserStaticProxy implements UserService
ProductService ProductStaticProxy implements ProductService
业务的模型越多,静态代理类就越多
程序员会额外写很多的静态代理类,增加程序员的负担
e.每个静态代理类都会创建很多代理对象
f.静态代理是在编译期间就确定了老业务和新业务的耦合关系
动态代理:(jdk动态代理,cglib动态代理)
jdk动态代理:是由jdk提供的功能
老的业务功能:
UserDao.java UserDaoImpl.java
UserService.java UserServiceImpl.java
新的业务功能:
TransactionMananger.java
目的:把新的功能添加到老业务功能,遵守开闭原则和单一职责原则
学习jdk动态代理的几个层次
1.能够写出jdk动态代理的代码
2.能清晰的了解jdk动态代理的调用关系 参见:jdk动态代理调用原理图.png
3.了解jdk的动态代理类的内容
jdk的动态代理流程
1.创建生成代理对象的类JDKProxy.java getProxyObject方法用户生成代理对象
2.创建InvocationHandler接口的子实现,在子实现中的invoke方法把老业务功能和新业务功能耦合
OldAndNewtogether.java invoke方法,耦合了新和老的业务
在jdk创建代理对象的之前,由jdk底层根据目标对象和目标对象所对应的接口,
创建出代理类,此代理类只是临时出现,用完就没有了,
创建完代理类,实例化此代理类的对象,Object proxyObject=Proxy.newProxyInstance(参数一,参数二,参数三);
只有调用Object proxyObject=Proxy.newProxyInstance(参数一,参数二,参数三);才会生成代理类和代理对象
下面是生成的代理类的模型:
/**
* jdk的代理类,由jdk的底层创建的
* @author Administrator
*
*/
public final class $Proxy0 extends Proxy implements UserService {
//静态代码块,m0---mx赋值 类型是Method
static {
try {
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.arno.service.UserService").getMethod("addUser",
new Class[] { Class.forName("com.tarean.entity.User") });
m4 = Class.forName("com.arno.service.UserService").getMethod("updateUser",
new Class[] { Class.forName("com.tarean.entity.User") });
return;
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
//若干私有属性
private static Method m0;//hashCode方法,从Object中获取
private static Method m1;//equals方法,从Object中获取
private static Method m2;//toString方法,从Object中获取
private static Method m3;//addUser方法,从UserService接口中获取
private static Method m4;//updateUser方法,从UserService接口中获取
//代理类构造
public $Proxy0(InvocationHandler paramInvocationHandler)throws {
super(paramInvocationHandler);
}
//重写UserService接口的addUser方法
public final void addUser(User user)throws{
try{
this.h.invoke(this, m3, new Object[] { user });
return;
}catch (Error|RuntimeException localError){
throw localError;
}catch (Throwable localThrowable){
throw new UndeclaredThrowableException(localThrowable);
}
}
//重写UserService接口的updateUser方法
public final void updateUser(User user)throws{
try{
this.h.invoke(this, m4, new Object[] { user });
return;
}catch (Error|RuntimeException localError){
throw localError;
}catch (Throwable localThrowable){
throw new UndeclaredThrowableException(localThrowable);
}
}
//equals方法
public final boolean equals(Object paramObject)throws {
try{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}catch (Error|RuntimeException localError){
throw localError;
}catch (Throwable localThrowable){
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()throws{
try{
return (String)this.h.invoke(this, m2, null);
}catch (Error|RuntimeException localError){
throw localError;
}catch (Throwable localThrowable){
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()throws{
try{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}catch (Error|RuntimeException localError){
throw localError;
}catch (Throwable localThrowable){
throw new UndeclaredThrowableException(localThrowable);
}
}
}
总结jdk动态代理:
1.原有的老业务,没有被破坏,符合单一职责 UserService.java
2.新的业务,符合单一职责 TransactionManager.java
3.创建一个java类用户生成代理对象JDKProxy.java
4.把新的业务要添加到老业务中
a.必须实现InvocationHandler接口 OldAndNewTogether.java
b.重写invoke的方法
c.在方法中把老业务和新业务耦合
5.一定要先由jdk生成代理类 参见:$Proxy0.java
6.由代理类生成代理对象
7.代理对象和目标对象是兄弟关系
代理类和目标类是兄弟关系
8.jdk动态代理要求目标类必须接口
9.jdk的代理类是在运行期间出现,一定不在编译期间出现
所谓的动态代理是代理类是动态出现的,什么时候调用,什么时候出现代理类
CGLIB动态代理:需要第三方库支撑
总结CGLIB动态代理:
0.需要额外第三方jar支撑
1.原有的老业务,没有被破坏,符合单一职责 UserService.java
2.新的业务,符合单一职责 TransactionManager.java
3.创建一个java类用户生成代理对象CGLIBProxy.java
4.把新的业务要添加到老业务中
a.必须实现MethodInterceptor接口 OldAndNewTogether.java
b.重写intercept的方法
c.在方法中把老业务和新业务耦合
5.一定要先由asm.jar生成代理类
6.由代理类生成代理对象
7.代理对象和目标对象是父子关系
目标类是代理类的父亲
目标类不能是final
8.cglib动态代理的目标类有无接口皆可
9.cglib的代理类是在运行期间出现,一定不在编译期间出现
所谓的动态代理是代理类是动态出现的,什么时候调用,什么时候出现代理类
jdk动态代理和cglib动态代理的主要区别:
jdk动态代理:
1.目标类必须有接口
2.代理对象和目标对象是兄弟关系
3.代理类是在运行期间动态创建的
4.创建代理对象快,用代理对象执行目标方法的时候是慢
5.jdk动态代理会把代理类缓存
cglib动态代理:
1.目标类有无接口皆可,但不能是final类
2.目标类是代理类的父类
3.代理类是在运行期间动态创建的
4.创建代理对象慢,用代理对象执行目标方法的时候快
代理就把新功能横切到原有业务上,在满足开闭原则和单一职责前提下
可以把新功能看成某一方面的功能,把某一个方面的功能横切到需要的业务上
spring aop的底层原理就是用的动态代理(有接口就用jdk,没有接口就用cglib)
提出问题:
jdk动态代理和cglib动态代理,把新功能横切到原有老业务中的所有方法上
能否把新功能横切到业务中的指定的一部分方法上,其他的业务方法不需要横切
答案:用spring aop可以对部分业务方法横切