文章目录
反射、动态代理与Spring的AOP
反射
看到一篇写的很好的文章
[java反射详解]: http://t.csdn.cn/wGVqm
代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。
程序为什么需要代理,代理长什么样?
1、对象如果嫌身上干的事情太多,可以通过代理来转移部分职责
2、对象有什么方法想被代理,代理就必须要有对应的方法
(一)静态代理
静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
(二)动态代理
代理类在程序运行时创建的代理方式被成为动态代理。
我们上面静态代理的例子中,代理类(studentProxy)是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。
实体类
public class BigStar implements Star{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String sing(String name) {
System.out.println(this.name + "正在唱:" + name);
return "谢谢大家!!!";
}
public void dance() {
System.out.println(this.name + "正在跳舞~~~");
}
public BigStar(String name) {
this.name = name;
}
}
代理接口
public interface Star {
String sing(String name);
void dance();
}
代理类
public class ProxyUtil {
public static Star createProxy(BigStar bigStar) {
/*
newProxyInstance(ClassLoader loader, 参数一 用于指定一个类加载器
Class<?>[] interfaces, 参数二 指定生成的代理是什么样子,也就是需要哪些方法
InvocationHandler h) 参数三 用来指定生成的代理对象要干什么事情
*/
Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
new Class[]{Star.class},
(proxy, method, args) -> {
if (method.getName().equals("sing")) {
System.out.println("准备话筒,收钱20万!");
} else if (method.getName().equals("dance")){
System.out.println("准备场地,收钱2000万");
}
return method.invoke(bigStar, args);
});
return starProxy;
}
}
实现类
public class Test {
public static void main(String[] args) {
BigStar s = new BigStar("刘德华");
Star starProxy = ProxyUtil.createProxy(s);
String rs = starProxy.sing("恭喜发财");
System.out.println(rs);
starProxy.dance();
}
}
/*
准备话筒,收钱20万!
刘德华正在唱:恭喜发财
谢谢大家!!!
准备场地,收钱2000万
刘德华正在跳舞~~~
*/
练习(动态代理)
**场景:**某系统有一个用户管理类,包含用户登录,删除用户,查询用户等功能,系统要求统
计每个功能的执行耗时情况,以便后期观察程序性能。
接口(需要实现的方法)
public interface UserService {
void login(String name,String password) throws Exception;
void deleteUsers() throws Exception;
String[] selectUsers() throws Exception;
}
接口实现类
public class UserServiceImpl implements UserService{
@Override
public void login(String name, String password) throws Exception{
if ("admin".equals(name) && "123456".equals(password)) {
System.out.println("登录成功,欢迎进入本系统");
} else {
System.out.println("登陆失败,用户名或密码错误!");
}
Thread.sleep(1000);
}
@Override
public void deleteUsers() throws Exception {
System.out.println("成功删除了1万个用户!");
Thread.sleep(1500);
}
@Override
public String[] selectUsers() throws Exception {
System.out.println("查询出3个用户");
String[] names = {"小凡","小七","小猫"};
Thread.sleep(3000);
return names;
}
}
代理工具类
public class ProxyUtil {
public static UserService createProxy(UserService userService) {
UserService userProxy = (UserService) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
new Class[] { UserService.class }, (proxy, method, args) -> {
if (method.getName().equals("login") ||
method.getName().equals("deleteUsers") ||
method.getName().equals("selectUsers") ) {
long begin_date = System.currentTimeMillis();
Object rs = method.invoke(userService,args);
long end_date = System.currentTimeMillis();
System.out.println(method.getName() + "方法执行耗时:" + (end_date - begin_date) / 1000.0 + "s");
return rs;
} else {
Object rs = method.invoke(userService,args);
return rs;
}
});
return userProxy;
}
}
实现类
public class Test {
public static void main(String[] args) throws Exception {
// UserService userService = new UserServiceImpl();
UserService userService = ProxyUtil.createProxy(new UserServiceImpl());
userService.login("admin","123456");
System.out.println("------------------------------------");
userService.deleteUsers();
System.out.println("------------------------------------");
String[] userNames = userService.selectUsers();
System.out.println("查询到的用户名为:" + Arrays.toString(userNames));
System.out.println("------------------------------------");
}
}
什么是AOP?
AOP为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理
实现程序功能的统一维护的一种技术。
AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍
生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序
的可重用性,同时提高了开发的效率。
常用术语:
Target(目标对象):代理的目标对象
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方
法类型的连接点
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知
Aspect(切面):是切入点和通知(引介)的结合合
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织入,而Aspect采用编译期织入和类装载期织入
AOP 的作用及其优势
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强
优势:减少重复代码,提高开发效率,并且便于维护
目标 + 增强(日志) = 切面
AOP 的动态代理技术
常用的动态代理技术
JDK 代理:基于接口的动态代理技术
cglib代理:基于父类的动态代理技术
tips: cglib的代理对象是目标对象的子类,而jdk代理对象和目标对象都实现了目标接口,jdk的代理对象还继承了Proxy