使用JavaConfig实现bean配置
正常我们在spring容器中注册一个Bean,我们需要去bean.xml中去配置,但是我们也可以用JavaConfig类,来去充当bean.xml的作用
首先,我们创建一个User类,@Component代表他是一个bean,方便让spring容器来扫描,@Value相当于之前在bean.xml中为我们注册的bean的属性来去赋值。

编写一个JavaConfig类来代替之前的bean.xml的作用,@Configuration代表它是一个配置类,@ComponentScan代表spring容器扫描bean的范围,@Import就是相当于把多个配置类合在一起,相当于之前的把多个bean.xml合在一起,@Bean就相当于我们之前在bean.xml中要注册的一个bean,方法名就是我们之前注册时bean的id,返回值的类型就相当于class

编写测试类,先得到context对象,然后再调getBean方法根据bean的id来得到bean,并得到其属性。

代理模式
为什么要学习代理模式?因为这就是SpringAOP的底层! [SpringAOP 和SpringMVC]
代理模式的分类:
静态代理
动态代理
静态代理
角色分析:
抽象角色:一般会使用接口或者抽象类来解决(房东要做的事,租房)
真实角色:被代理的角色(房东)
代理角色:代理真实角色代理真实角色后,我们一般会做一些附属操作(中介,帮房东执行想做的事:租房,附属操作:看房、签合同等)
客户: 访问代理对象的人!(跟中介去谈租房的事情,不经过房东)

理解静态代理的小demo
写抽象角色,也就是房东要做的事:租房,用接口来解决,写一个租房接口

写真实角色:房东,它去实现租房接口,定义租房接口的具体操作。

如果我们不通过中介去租房,直接新建一个房东对象,调用他的租房方法即可

但是,房东不想去带客户看房,写合同这些杂事,所以交给中介(代理角色)去做了
我们创建一个代理类,也实现租房的接口,其中有房东的属性,以及有参构造器,用来方便传房东属性的值,还定义了一个租房方法,实际内部执行的核心就是房东(真实角色的该方法)的租房方法。但是,这个代理类也实现了很多增加的方法,比如房东不愿意做的带客户看房,签租赁合同,收中介费等,把这些方法也一起写在代理类执行租房方法的里面。

编写客户端,房东要租房子了,先new一个房东对象,然后创建一个代理对象,并传入房东信息,客户直接面对中介(代理对象)去租房就可以了,我们会发现,代理对象执行房东的租房操作后,不光租了房,而且把看房,签合同等这些多的事也都干了。这就是代理模式的意义,在不改变真实对象操作的基础上,增强真实对象的方法。

深入理解静态代理的demo
创建一个抽象角色,增删改查的接口

创建一个真实角色(房东),去实现上面的增删改查接口,并写出各个增删改查方法的具体操作。

如果不走代理,在客户端,直接新建一个这个真实对象类,调用相应方法即可。

如果说,我们想在本来功能的基础上,在每个方法里增加一个日志功能,如果不用代理模式,则我们需要在真实对象里的每个对应方法中加上对应的代码,才能实现,非常麻烦。也改变了原有的业务代码。

我们只需要新建一个代理对象类,实现增删改查接口,有一个可注入一个真实角色的属性,然后在其中定义一个日志功能的方法,在自己增删改查方法的基础上,除了调用真实角色的增删改查方法,还在每个上面加上自己的日志方法。(图中有误地方依次应为userService.delete、userService.update、userService.query),这样就没有改变原有真实对象的业务代码,而且在原有代码的基础上增加了日志功能。这就是代理模式的好处。

动态代理
动态代理和静态代理角色一样
动态代理的代理类是动态生成的,不是我们直接写好的!
动态代理分为两大类: 基于接口的动态代理,基于类的动态代理
基于接口---JDK动态代理[我们在这里使用]
基于类: cglib
java字节码实现 : javasist
需要了解两个类: Proxy:代理,InvocationHandler: 调用处理程序
理解动态代理的小demo
创建一个抽象角色,租房接口

创建一个真实角色(房东),来实现租房接口,并定义租房方法的实际操作。

之前静态代理的话,我们是需要创建一个代理对象的,不同的真实对象,我们就需要创建一个不同的代理类,非常麻烦

动态代理的话,我们只需要创建下面这个类,去实现InvocationHandler,有一个被代理的接口属性,有set方法可以注入值,有一个可以生成得到代理类的方法,还有一个处理代理实例并返回结果的方法,这块就相当于之前代理角色,在自己的方法中执行代理的真实对象的方法一样。

如果我们要增强本身真实对象的业务代码,我们只需要在这个动态代理类中加入我们需要增强的方法,例如看房子,收中介费,然后将该方法加入到invoke方法中,method.invoke就相当于之前在代理对象方法中调用真实对象执行真实对象的方法,我们将增强的方法放在它的上面或下面即可。

我们编写客户端,先new一个我们需要租房的真实对象,我们再new一个刚才创建的动态代理类,得到这个对象,此时还有没有代理对象,我们先需要用set方法将真实对象传入其中,再调得到代理对象的方法getProxy()得到代理对象,然后我们客户直接面向代理对象,去执行对应的租房方法即可,可以看到,租房方法在真实对象租房方法的基础上增强了,看房子和收中介费方法。

深入理解动态代理的demo
创建一个抽象角色,增删改查的接口

创建一个真实角色(房东),去实现上面的增删改查接口,并写出各个增删改查方法的具体操作。

编写动态代理类

在客户端,new一个我们需要的真实角色,new一个我们刚创建的动态代理类,把这个真实角色通过set方法注入动态代理对象中,然后调用获得代理对象方法,得到代理对象后,通过代理对象执行我们想要的方法。增加也好,删除也好。


我们想在真实对象的方法基础上,增加日志功能。在动态代理类中定义一个日志方法,然后在method.invoke上加上该方法即可。

我们在客户端再通过代理对象执行增加方法,即可看到,我们增加的日志方法已经被增加上。

总结
代理模式好处
可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
公共业务就交给代理角色!实现了业务的分工!
公共业务发生扩展的时候,方便集中管理!
静态代理缺点
一个真实角色就会产生一个代理角色;代码量会翻倍~开发效率会变低
动态代理优点
一个动态代理类代理的是一个接口,一般就是对应的一类业务
一个动态代理类可以代理多个类(多个真实角色),只要是实现了同一个接口即可!