Spring最重要的两个特点:1.依赖注入;2.切面编程,aop编程。

1.依赖注入是什么?为什么要有依赖注入?

  依赖注入就是我们要使用某个对象,不是我们自己在程序里面通过new生成对象,而是通过Spring容器加载配置文件ApplicationContext.xml等生成对象;Spring容器帮助我们管理对象的创建,调用与回收;

 

Java spring 关键字 spring两个关键特性_配置文件

 对于依赖的对象要自己在构造函数里面生成 

this.quest = new

这样使程序紧耦合,RescueDamselKnight只能处理RescueDamselQuest的任务,不能处理其他Quest实例 ,这样不利于组件重组,代码利用率比较低且不利于维护;

Java spring 关键字 spring两个关键特性_代理类_02

  接口被传入进来,具体传进来的是什么根据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});
        }