我们都知道Spring的两大核心技术:依赖注入(DI)和面向切面编程(AOP)
控制反转(IOC)是一种思想,不是技术,它是由DI技术实现的。
在了解这两技术之前我们先来了解一下什么是容器
控制反转是一种思想,它的实现主要靠依赖注入(DI)。
在传统应用程序中,我们在类的内部创建对象,这样使类与类之间关系紧密,耦合度较高。
IOC思想则是把对象的创建、装配和管理都交给容器来控制。目的就是松散耦合,使程序结构更灵活。
例如,Servlet技术也是控制反转(IOC)思想的一种体现。
在Servlet技术中:
1、你要创建一个类继承HttpServlet类;
2、在配置文件web.xml中注册servlet
<servlet-name>myServlet</servlet-name>
<servlet-class>com.bjpowernode.controller.myServlet</servlet-class>
在这个过程中没有创建过Servlet对象,我们只是在配置文件中注册Servlet,实际上是Tomcat容器帮我们创建的。
总结: 在使用Spring之前,当一个类A要调用另一个类B的方法时,就会在自己的类中new B(),需要哪个对象就创建哪个对象,A会对B产生依赖,导致程序之间的耦合度较高,而且不灵活。在Spring之后,A不需要在自己创建B对象了,把这个工作交给一个第三方Spring容器控制,Spring容器会创建好B,在A需要时,从Spring容器中取出B交给A,也实现了A对B的依赖,至于什么时候创建B什么时候取出,都是容器的工作,也就是把以前A自己掌握的控制权现在移交给Spring容器了。这也就是控制反转的思想。
DI是如何实现的呢?或者叫容器是如何创建对象的
主要有两种方式:主要通过配置文件和注解
1、配置文件的方式:set注入
一个bean标签的声明就对应一个对象,下图的方式是通过在配置文件中使用set方法注入property标签实际是调用了Sutdent中的set方法实现的赋值。这是比较常用的一种赋值方式
所有的通过bean标签声明的对象都具有单例性,id唯一,实际是拿到了bean中的class属性,通过反射创建对象,property给对象的属性赋值,Spring会把通过bean创建的对象都保存到一个map容器中,key保存的就是bean的id(对象名),value保存的是对象的实例,当需要用哪个对象时通过getBean(“id”)方法就可以获取对象。
2、还有一种是配置文件的构造注入:
通过< constructor-arg >标签的个数来找对应的构造方法,并且对应好参数列表,通过构造器的方式实现给对象赋值。
如果是引用类型的参数那么标签中的value换成ref即可。
配置文件实现注入的这种方法也有弊端,代码量增多,不方便阅读,需要结合代码和xml文件一起看,优点是,对于需要频繁修改的可以放在配置文件中,减少修改源代码的次数。
步骤
1、使用注解首先要添加依赖,spring-context这个包中包含了spring-aop这个依赖,有spring-aop才可以使用注解。
2、添加注解
3、在配置文件中加入组件扫描器,扫描注解的位置。
@Component(value=“student”)
括号里的可省略,默认为类名的首字母小写,这个注解用在类上相当于声明bean,用于创建对象
@Value(value=“张三”):定义在属性上的,通过这个注解就不需要set方法了,原理也是通过反射实现的。
@Repository:放在dao层的实现类上面,表示创建dao对象,dao对象是进行数据库访问的,又叫持久层注解。
@Service:放在业务层的实现类上面,创建Service对象,业务层是处理业务逻辑的。
@Controller:放在控制层上面,创建Controller对象的,控制层用来提交用户信息或者接受返回数据的。
这三个注解即创建对象,同时也把程序进行了分层处理。
@Autowired(required=true)是Spring框架提供的注解,用于引用类型的自动注入(也是创建对象),以byType的方式;
括号里的可以省略,默认是true,表示对象创建失败,程序报错并停止,false表示如果对象创建失败,不提醒报错,但是可能会出现空指针异常。
这个可以搭配使用@Qualifier(“studentDao”)用来表示实例化的对象名
@Resource注解与上面的有些不同,他是JDK中提供的,而不是Spring,但是Spring支持他的使用,@Resource也是用来给引用类型自动注入的,它优先使用byName的方式,如果没有找到名字再使用byType的方式。
注解的优点:代码简洁易读,但是需要频繁修改对象属性时,还是推荐使用配置文件的方式
AOP 全拼:Aspect Object Programming
AOP编程技术不是Spring独有的,Spring框架是支持AOP编程的框架之一,关系不要搞混。
AOP的目的是在不修改源代码的基础上实现功能的拓展。
AOP编程往往被定义为促使软件系统实现关注点分离的一项技术。
这个关注点就是指一个业务模块中实现核心业务逻辑的代码,这个核心才是程序应该关注的。同时还会有日志、事务管理、安全等具有辅助功能的重复代码,每个业务模块中都会有这样的重复代码,我们把这种具有辅助功能的重复代码与核心业务代码分开就是AOP编程要解决的问题。
我们把这种具有辅助功能的重复代码抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect)。
如果我们把核心代码与具有辅助功能的代码分离开,可以实现横切关注点与它们所影响的对象之间的解耦,使服务模块更简洁,因为它们只包含核心代码,而把日志,事务管理等代码转移到切面中。
DI有助于应用对象之间的解耦,而AOP可以实现横切关注点与它们所影响的对象之间的解耦。
AOP常用术语
AOP变成就是动态代理实现的。
两种方式:JDK动态代理和CGLIB动态代理。
更详细的可以查看这篇文章《Java设计思想——反射机制》中的invoke方法
1、JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
2、如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库(或者说是一个工具类),可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。