Spring是一个轻量级的控制反转和面向切面的容器框架。可以支持任何类型的Java企业级应用的开发。并且可以容易地整合其他开源框架,比如springmvc,mybatis,structs,hibernate等等。
ioc的表面意思就是控制反转,就是将创建和管理bean的控制过程交给spring ioc容器管理,而不是通过代码手动管理。Spring框架的核心是Spring 容器。容器负责创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的组件。容器通过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据可以通过 XML,Java 注解或 Java 代码提供。
1.ioc容器负责创建对象
2.ioc容器负责管理bean的生命周期
如何完成依赖注入?
主要的方法:
ioc容器主要有两种
BeanFactory
ApplicationContext
ApplicationContext是BeanFactory的子接口,所以顺理成章地ApplicationContext的功能要更为丰富一些。二者主要的区别如下
最主要的区别就是BeanFactory使用延迟加载,用到某个bean才去添加到容器中然后使用,而ApplicationContext则是在spring启动时一次性将所有的bean添加到容器中,随时使用。
支持延迟加载和即时实例化多种方式。
实现对象之间关系的解耦。
利用工厂模式加反射即可实现
工厂类中提供一个通过传参的名字反射得到一个bean对象的方法。调用的时候直接通过传入类名参数即可获得对象的bean。
/**
* 工厂模式 + 反射实现spring ioc
* ioc目标,从元数据当中得到类的路径的字符串信息,就可以实例化这个类的对象
*/
interface UserService{
void login(String username);
}
class UserImpl implements UserService{
@Override
public void login(String username) {
System.out.println("普通用户:"+username+"登录成功了");
}
}
class AdminImpl implements UserService{
@Override
public void login(String username) {
System.out.println("管理员:"+username+"成功登录了后台");
}
}
class Factory {
public static UserService getInstance(String ClassName){
UserService userService = null;
try {
userService = (UserService) Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return userService;
}
}
public class Client{
public static void main(String[] args) {
UserService userService = Factory.getInstance("com.jzx.shejimoshi.AdminImpl");
if(userService != null){
userService.login("admin");
}
}
}
Spring ioc容器集中管理的对象。由ioc容器进行实例化。装配和管理。
bean的创建时根据用户配置的元数据来进行的。元数据包括注解、xml配置文件等等。
xml配置bean
<bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
<property name="name" value="Edureka">property>
bean>
注解配置bean:
先开启基于package的注解扫描
<beans>
<context:component-scan base-package="com.test">context:component-scan>
beans>
然后在相应的com.test包下的类上面打上相应的标签即可,常用的有@Controller @Service @Component @Repository等
若使用BeanFactory的话,那么只支持两种:
Singleton和Prototype,其实最常使用的就这两种。
一种是单例,一种是每次请求这个bean都产生一个实例。
若使用了ApplicationContext,那么包括五种。
除了上面的两种,还包括request, session,global session
request:每个http请求使用一个bean
session:每个http请求使用一个bean,并且只在这个http的session内有效
global session:概念类似于分布式部署的时候的session
七种,最常用:REQUIRED和REQUIRED_NEW,分别代表:
REQUIRED:若当前存在事务,则加入这个事务,若当前不存在事务,则新起一个事务。
REQUIRED_NEW:不管当前存在不存在事务,都新起一个事务执行。
其他:
NOT_SUPPORTED:不使用事务,有事务则挂起
NEVER:不使用事务,有事务则抛出异常。
SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
五种:一种为读取的数据库的隔离级别,数据库设置为什么就是什么。
另外四种和常见的隔离级别相同:
1.读未提交–>产生脏读,不可重复读,幻读
2.读已提交–>产生不可重复读和幻读 :Orcale默认
3.可重复读–>产生幻读 :MySQL默认
4.串行化–>避免所有
首先将aop就要讲清楚他是干什么的,有什么用。aop直译就是面向切面编程。
切面是什么呢?可以想象一下一块豆腐被随意切了一刀,但是刀没有抽出来,这时候这个刀所代表的就是切面。切面代表的是在所有切入点上面的增强的通用代码逻辑。
切面包括了切点和通知,切入点就是明确的类和方法名,或者通过正则表达出的类和方法。通知就是切面实际的工作。包括如下几种通知:
前置通知,后置通知,返回通知,异常通知,环绕通知。
先来看静态代理:
一个接口同时被两个类实现,其中一个是代理类,其中一个是实际的类。
代理类中加入实际类对象的属性,并作为构造器的参数。重写接口的方法,对实际类中的方法进行增强。并且可以有自己独特的方法。下面是例子。
interface Singer{
void sing(String song);
void jump(int steps);
}
class Ikun implements Singer{
@Override
public void sing(String song) {
System.out.println("ikun唱"+song);
}
@Override
public void jump(int steps) {
System.out.println("ikun跳"+steps+"下");
}
}
class IkunProxy implements Singer{
private Ikun ikun;
public IkunProxy(Ikun ikun){
this.ikun = ikun;
}
@Override
public void sing(String song) {
System.out.println("ikun经纪人介绍歌曲"+song);
ikun.sing(song);
System.out.println("ikun经纪人宣布唱完了");
}
@Override
public void jump(int steps) {
System.out.println("ikun经纪人介绍他要跳"+steps+"下");
ikun.jump(steps);
System.out.println("ikun经纪人宣布跳完了");
}
public void special(){
System.out.println("ikun经纪人的特殊活动");
}
}
public class TestProxy {
public static void main(String[] args) {
Ikun ikun = new Ikun();
IkunProxy ikunProxy = new IkunProxy(ikun);
ikunProxy.sing("鸡你太美");
ikunProxy.jump(10);
}
}
运行结果
ikun经纪人介绍歌曲鸡你太美
ikun唱鸡你太美
ikun经纪人宣布唱完了
ikun经纪人介绍他要跳10下
ikun跳10下
ikun经纪人宣布跳完了
动态代理:jdk(实现invocationhandler)和cglib的方式