关于spring,应该重点掌握的就是spring的两大特性,控制反转和切面编程
控制反转(IOC):
在spring之前,我们创建对象都是自己手动new出来的,比如:
User user = new User();
这是之前我们创建对象的常用方式,而spring将这个过程进行了封装,帮我们创建对象,而我们需要使用的时候只需要去spring的容器中获取就可以了。
UserDao userDao = (UserDao)BeanFactory.getBean(beanName:"userDao");
看起来好像比之前的更复杂了,但是这样做却把程序间的耦合度降低了。
这就是所谓的控制反转。
控制反转(IOC)
那么spring是如何实现控制反转的呢?——反射
控制反转实现原理
利用反射机制创建对象
//用于创建Bean对象
public class BeanFactory {
//定义一个Properties对象
private static Properties pros;
//定义一个Map,用于存放要创建的对象。称之为容器
private static Map<String,Object> beans;
//使用静态代码块为Properties赋值
static{
try {
//实例化对象
pros = new Properties();
//获取Properties文件的流对象
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
pros.load(in);
//实例化容器
beans = new HashMap<String, Object>();
//取出配置文件中所有的key
Enumeration keys = pros.keys();
//遍历枚举类型
while(keys.hasMoreElements()){
//取出每个key
String key = keys.nextElement().toString();
//获取key的value
String beanPath = pros.getProperty(key);
//通过反射创建对象
Object value = Class.forName(beanPath).newInstance();
//把bean和value存入容器之中
beans.put(key,value);
}
}catch(Exception e){
throw new ExceptionInInitializerError("初始化properties失败");
}
}
//根据bean名称获取bean对象
public static Object getBean(String beanName) {
//beans是一个map集合,里面存放了bean对象,单例
return beans.get(beanName);
}
}
读取配置文件,获取配置文件中key所对应的value,也就是类的全限定路径名,在通过反射机制创建出对象
bean.properties:
accoutService = cn.fzkj.service.Impl.AccoutServiceImpl
accoutDao = cn.fzkj.dao.Impl.AccoutDaoImpl
切面编程(AOP)
基于代理思想,对原来的对象创建代理对象,从而在不改变原来代码的基础上对原有方法进行增强。
主要的应用场景:
- 记录日志
- 性能监控
- 权限控制
- 缓存优化
- 事务管理
切面编程的实现原理
spring中的切面编程的实现主要有两种方式:
1.JDK动态代理
2.Cglib动态代理
- JDK动态代理
代理类:
public class Client {
public static void main(String[] args) {
final IProducer pro = new Producer();
/**
* 动态代理:
* 特点:随用随创建,随用随加载
* 作用:不修改源码的基础上对方法进行加强
* 分类:
* 1.基于接口
* 2.基于子类
* 基于接口的动态代理:
* 涉及的类:Proxy
* 创建代理对象:
* proxy类中的newProxyInstance方法
* 创建代理的要求
* 被代理类最少实现一个接口
* newProxyInstance的参数:
* ClassLoader:
* 用于加载代理对象字节码,和被代理对象使用相同的类加载器
* class[]:字节码数组
* 让代理对象和被代理对象有相同的方法
* InvocationHandler:用于提供增强的
* 让我们写如何代理,一般写一个该接口的实现类,通常是匿名内部类
* 此接口的实现类是谁用谁写
*/
IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(pro.getClass().getClassLoader(),
pro.getClass().getInterfaces(),
new InvocationHandler() {
/**
* 作用:执行被代理对象的任何接口方法都会经过这个方法
* proxy:代理对象的引用
* method:当前执行的方法(描述对象)
* method.invoke(被代理对象,实际参数)
* args:当前执行方法所需的参数
* 返回值:和被代理对象有相同的返回值
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//提供增强的代码
Object returnValue = null;
//1.获取方法执行的参数
Float money = (Float)args[0];
System.out.println("前置");
//2.判断当前执行的方法是否是销售
if("saleProduct".equals(method.getName())){
returnValue = method.invoke(pro,money*0.8f);
}
return returnValue;
}
});
proxyProducer.saleProduct(10000f);
}
}
service:
public class Producer implements IProducer {
//销售
public void saleProduct(Float money) {
System.out.println("拿到钱:"+money+",销售产品");
}
//售后
public void afterService(Float money){
System.out.println("提供售后,并拿到钱:"+money);
}
}
运行结果:
- Cglib动态代理
代理类:
public class Client {
public static void main(String[] args) {
final Producer pro = new Producer();
/**
* 动态代理:
* 特点:随用随创建,随用随加载
* 作用:不修改源码的基础上对方法进行加强
* 分类:
* 1.基于接口
* 2.基于子类
* 基于子类的动态代理:
* 涉及的类:Enhancer
* 创建代理对象:
* Enhancer类中的create方法
* 创建代理的要求
* 被代理类不能是最终类
* create的参数:
* Class:字节码
* 指定被代理对象的字节码
* Callback:用于提供增强
* 一半写的是该接口的子接口实现类
*/
Producer cglibProducer = (Producer) Enhancer.create(pro.getClass(), new MethodInterceptor() {
/**
* 执行被代理对象的方法都会经过这个方法
* @param proxy
* @param method
* @param args
* @param methodProxy :当前执行方法的代理对象
* @return
* @throws Throwable
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//提供增强的代码
Object returnValue = null;
//1.获取方法执行的参数
Float money = (Float)args[0];
System.out.println("前置");
//2.判断当前执行的方法是否是销售
if("saleProduct".equals(method.getName())){
returnValue = method.invoke(pro,money*0.8f);
}
return returnValue;
}
});
cglibProducer.saleProduct(10000f);
}
}
Producer类:
public class Producer {
//销售
public void saleProduct(Float money) {
System.out.println("拿到钱:"+money+",销售产品");
}
//售后
public void afterService(Float money){
System.out.println("提供售后,并拿到钱:"+money);
}
}
运行结果:
spring的ioc和aop就结束了。
扩展:
aop中代理的实现,即spring是如何给目标对象创建代理类的
一个主方法:
public class Client {
public static void main(String[] args) {
final Producer pro = new Producer();
Producer p = (Producer) new CglibProxyFactory(pro).getProxyInstance();
p.saleProduct(10000f);
}
}
可以看出,通过CglibProxyFactory类的getProxyInstance()方法得到的就是一个代理对象。
CglibProxyFactory类:
//创建代理类
public class CglibProxyFactory {
//初始化对象
private Object target;
public CglibProxyFactory(Object target){
this.target = target;
}
//创建代理对象
public Object getProxyInstance(){
return Enhancer.create(target.getClass(), new MethodInterceptor() {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("开始事务");
Float money = (Float)args[0];
Object returnValue = method.invoke(target, money*0.8f);
System.out.println("提交事务");
return returnValue;
}
});
}
}
运行结果:
持续更新~~~