Spring最重要的两个特点:1.依赖注入;2.切面编程,aop编程。
1.依赖注入是什么?为什么要有依赖注入?
依赖注入就是我们要使用某个对象,不是我们自己在程序里面通过new生成对象,而是通过Spring容器加载配置文件ApplicationContext.xml等生成对象;Spring容器帮助我们管理对象的创建,调用与回收;
对于依赖的对象要自己在构造函数里面生成
this.quest = new
这样使程序紧耦合,RescueDamselKnight只能处理RescueDamselQuest的任务,不能处理其他Quest实例 ,这样不利于组件重组,代码利用率比较低且不利于维护;
接口被传入进来,具体传进来的是什么根据Spring容器决定(Quest可以有很多实现);使用的是哪个具体的Quest,BravaKnight并不知道,只有配置文件才晓得。Spring项目里面也是通过注解@Autowired Interface,生成实现该接口的一个实例,而具体由谁实习该接口,配置文件里面会定义。
2. 为什么需要AOP编程?
aop,面向切面编程,这个是对oop(面向对象编程)的补充;oop是用来完成核心业务逻辑,但是有一些公共性的行为,比如日志,权限验证等可能在很多对象里面里面都有用到,我们不能在这些对象的程序里面把日志和权限验证的代码都写一遍,这样太繁琐了而且对象之间的耦合性很高。所以我们把这些公共性的行为抽象封装起来,在配置文件里面决定在哪些地方使用这些行为。
2.1动态代理实现aop编程
接口IHello
public interface IHello{
public void sayHi(String str);
}
实现IHello的类
public class Hello implements IHello {
public void sayHi(String str){
System.out.println(str);
}
}
我们想在方法sayHi()的前后添加一些操作,一个方法就是新建一个对象HelloCon。
public class HelloCon implements IHello{
private IHello hello;
public HelloCon(IHello hello){
this.hello = hello;
}
public void sayHi(String str){
//操作1
hello.sayHi(str);
//操作2;
}
}
另一个方法是我们使用代理模式访问Hello对象,与该代理对象绑定有一个InvocationHandler接口,我们重写该接口,操作1,操作2放在invoke()方法里面完成;实现代理主要分为两部分:1.生成代理对象;2.重写InvocationHandler的invoke()方法。
public class HelloHander implements InvocationHandler{
public IHello hello;
public HelloHander(IHello hello){
this.hello = hello;
}
public Object getProxyObject(){
return Proxy.newProxyInstance(
this.getClass().getClassLoader(),IHello.class,this);
}
//proxy:与该Handler绑定的代理对象;
//method:使用反射来实现代理对象对真实对象方法的调用
//args:方法的形参
public Object invoke(Object proxy, Method method, Object[] args) {
//操作1
method.invoke(hello,args);
//操作2
return null;
}
}
/*
loader:用来定义代理类的类装载器
interfaces:代理类实现的接口
h:实际处理的内容放在h里面
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{
//将代理类将要实现的接口的字节码复制到intfs中
final Class<?>[] intfs = interfaces.clone();
//如果这个代理类已经存在(该代理类由loader定义,并且实现了给定的接口),直接复制缓存返回即可,如果不存在,通过ProxyClassFactory创建新的代理类
Class<?> cl = getProxyClass0(loader, intfs);
// 得到构造函数;constructorParams的构造函数是 //constructorParams(InvocationHandler.class)
final Constructor<?> cons = cl.getConstructor(constructorParams);
//构造函数生成新的代理对象,传入的参数是代理对象要关联的invocationhandler
return cons.newInstance(new Object[]{h});
}