1.什么是spring?

1.在spring出现之前曾经使用过EJB开发JAVA EE应用的人,一定知道,EJB开始的学习和应用非常的艰苦,很多东西都不能一下子就很容易的理解,spring出现的初衷就是为了解决这些问题
2.2002年一个叫Rod Johnon 的人写了一篇文章,很多人根据这篇文章产生一些感悟,然后产生了spring

2.spring两大基本核心

1.IOC(依赖注入)或DI(控制反转)

IOC(控制反转)就是依赖注入(DI):反转的是获取对象的方式,将创建对象、属性值的方式进行了反转,从new反转为了从springioc容器getBean()
依赖注入(DI):将属性值注入给了属性,将属性注入给了bean,将bean注入给了ioc容器
总结:Ioc是Spring的一个容器,他不是一种技术,而是一种思想,依旧是基于面向对象编程的。它能指导我们怎么样设计出松耦合、更优良的程序。
简单来说,如果现在有两个(甚至更多)类,A类和B类,A类要引用B类中的某个方法,传统编程是在A类中实例化一个B类,也就是通过new,然后打点调方法,而我们知道,代码高耦合最大的原因就是用了new。利用Spring框架就将实例化的过程交给了IoC容器,通过配置文件中的设置Bean或者B类中添加注解,A类可以不new通过ApplicationContext的getBean方法得到实例,然后打点调方法就可以了,减少了两个类之间的耦合度。

2.AOP(面向切面编程)

当一个方法在每个类中都会执行,我们就可以把这个方法提出来然后再切入需要使用这个方法的地方,降低了耦合度 ,也利于后期维护。

3.开发spring所需要的jar包(5个基本+1个日志jar)

1.spring-aop.jar (开发aop特性需要的jar)
2.spring-beans.jar (处理bean需要的jar)
3.spring-context.jar (处理spring上下文需要的jar)
4.spring-core.jar (spring核心jar)
5.spring-expression.jar(spring 表达式 jar)
6.commons-logging.jar (第三方日志jar)

4.使用bean实现依赖注入(非注解)

1.首先在src下创建一个名为ApplicationContext.xml的springxml文件
2.写bean标签 id=bean的名字 class=类的全类名,一个bean代表一个类,bean里的property子标签代表属性 name=属性名 value=属性值,配置好这个就意味着这个类已经在ioc容器内了当想要使用这个类直接获取:
ApplicationContext context =new ClassPathXmlApplicationContext("ApplicationContext.xml");
	context.getBean("bean的id");

5.依赖注入的三种方式(非注解)

1.set注入:通过setXxx赋值:

<property…>
赋值,默认使用的是set方法,依赖注入底层是通过反射实现的

2.构造器注入:通过构造方法赋值:

,注意的顺序必须和构造方法参数的顺序保持一致
如果不一致可以指定index属性按照构造方法的顺序,也可以指定type

3.p命名空间
<bean id="course" class="entity.Course" p:courseHour="300" p:courseName="hadoop">

简单类型:p:属性名="属性值"
引用类型:(除了string外):p:属性名-ref=“引用的id”
注意:1.多个p赋值的时候要有空格。
2.无论是String还是int/short/long,在赋值时都是value=“值”,因此建议此种情况需要配合name/type进行区别

注入各种集合类型:List Set map properties
set、list、数组 各自都有自己的标签,但是也可以混着用

给对象赋值null:使用标签

<property name="name">
	<null></null>
</property>

赋空值" " :value里不写东西

<property name="name">
	<value></value>
</property>

ioc中定义bean的前提:该bean的类必须提供了无参构造
自动装配(只适用于ref类型):在bean里面定义autowire=“byName|byType”
byName:会自动寻找其他bean的id值和Course类的属性名
byType:其他bean的类型(class)是否与该course类ref属性类型一致(注意,此种方式必须满足:当前ioc容器中只能有一个bean满足条件)
constructor:其他bean的类型(class)是否与该course类的构造方法参数的类型一致;此种方式的本质就是byType

使用注解定义bean:通过注解的形式将bean以及相应的属性值放入ioc容器
可以在头文件中一次性将ioc容器的所有bean 统一设置成自动装配

<beans xmls=........     default-autowire="byName">

6.使用注解实现ioc容器

通过注解的形式将bean以及相应的属性值放入ioc容器

<context:component-scan base-package="xxx.xxx">
</context:component-scan>

Spring在启动的时候会根据base-package在该包中扫描所有类,查找这些类有没有注解,如果有将这些类加入ioc容器
@Component(“id”)等价于

<bean id="id" class="类绝对限定名"></bean>

@Component(“id”)细化:
dao层注解:@Repository(仓库)
service层注解:@Service
控制器层注解:@Controller

如果想使用byType:
@Autowired(自动装配,byType)
@Qualifierz(“xxxx”)(byName)
如果想使用byName:
只写@Autowired(自动装配,byName)

7.使用注解实现事务(声明式事务)

1.增加对事务的支持

<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>

配事务管理器(txManager)依赖于DataSource,DataSource数据库连接字符串
2.使用
@Transactional(readOnly=false,propagation = Propagation.REQUIRED)
将需要成为事务的方法前增加注解@Transactional
配置事务的传播行为:Propagation=Propagation.xxx
默认是REQUIRED,即使用调用方法的事务
REQUIRES_NEW,开启一个新的事务,使用自己的事务,调用方法的事务被挂起
例子:
A事务:买书操作(REQUIRED)
B事务:买书造成的库存减少操作(REQUIRES_NEW)
A事务执行时,碰到B事务,A事务暂时被挂起,去开启一个新的事务去执行B事务,如果B事务失败了A不一定失败,如果使用不开启新的事务,整体看成一个事务要么全成功要么全失败,B回滚A也回滚

8.AOP(非注解)

前置通知实现:

a.jar
aopaliance.jar
aspectjweaver.jar
b.配置
1.写一个方法继承MethodBeforeAdvice类重写方法:

@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("前置通知---");}

2.在xml进行配置(注意要在命名空间加入aop)
(1)将业务类和通知加入ioc容器
(2)配置切到哪里和通知

<aop:config>
	<aop:pointcut expression="execution(public void service.impl.StudentService.addStudent(entity.Student))" id="pointcut"></aop:pointcut>
	<aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"></aop:advisor>
</aop:config>

c.编写
aop:每当执行add(); 之前自动执行一个方法log();
add();业务方法
before();自动执行的通知,即aop前置通知

后置通知实现:

1.继承AfterReturningAdvice类重写方法

@Override
	public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
	System.out.println("前置通知。。。目标对象:"+target+",调用的方法名"+method.getName()+"方法的参数个数:"+args.length+",方法的返回值"+returnValue);
	}
异常通知实现:

1.需要继承ThrowsAdvice类编写方法

public void afterThrowing(Method method,Object[] args,Object target ,Throwable ex) {
		System.out.println("异常通知:目标对象:"+target+",方法名:"+method.getName()+",参数个数:"+args.length+",异常类型"+ex.getMessage());
	}

根据异常通知解耦的定义可以发现,异常通知的实现类必须编写以下方法:

public void afterThrowing([Method,args,target],ThrowableSubclass)
1.public void afterThrowing([Method,args,target],ThrowableSubclass)
2.public void afterThrowing(ThrowableSubclass)
环绕通知实现:

环绕通知:在目标方法的前后、异常发生时、最终等各个地方都可以进行的通知,最强大的一个通知;可以获取目标方法的全部控制权(目标方法是否执行、执行之前、执行之后、参数、返回值等)
1.继承MethodInterceptor类重写方法

@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
	//方法体1
	Object result=null;
	try {
		System.out.println("环绕通知实现的【前置通知】");
		//invocation.proceed()之前的代码:前置通知、之后的:后置通知、捕获异常的:异常通知
		 result =invocation.proceed();//控制着目标方法的执行,addStudent();写这个方法就代表执行addstudent
	//	result就是目标方法的返回值
		System.out.println("环绕通知实现的【后置通知】");
		//方法体2
	}catch(Exception e) {
		//方法体3
		System.out.println("环绕通知实现的【异常通知】");
	}
	return result;
}

9.AOP(注解方式)

1.写一个类,在类使用@Aspect注解,说明这个类是一个通知类
2.写一个方法,在方法上面使用@Before(前置通知)、

@AfterReturing(后置通知)、
@Around (环绕通知)、
@AfterThrowing(异常通知)、
@After(最终通知)
四个通知的实现:

@Before("execution(public * addStudent(..))")//加一个before说明是是前置通知属性,定义切点
	public void before() {
		System.out.println("注解实现的前置通知");
	}
	
	@AfterReturning("execution(public * addStudent(..))")//加一个@AfterReturning说明是是后置通知属性,定义切点
	public void after() {
		System.out.println("注解实现的后置通知");
	}
	
	@Around("execution(public * addStudent(..))")//加一个@Around说明是是后置通知属性,定义切点
	public void around(ProceedingJoinPoint pj) {
		//前置通知
		try {
			//方法执行
			pj.proceed();//控制方法执行
			//后置通知
		}catch(Throwable e) {
			//异常通知
		}finally {
			//最终通知
		}
	}
	@AfterThrowing("execution(public * addStudent(..))")//加一个@AfterThrowing说明是是后置通知属性,定义切点
	public void throwing() {
		System.out.println("注解实现的异常通知");
	}
	@After("execution(public * addStudent(..))")
	public void final1() {
		System.out.println("注解实现的最终通知");
	}
3.在这个类上面写一个@Component(“name”)方法,将这个类加入ioc容器
4.在xml配置
<aop:aspectj-autoproxy ></aop:aspectj-autoproxy> <!-- 写这句话说明开启注解对AOP的支持 -->

10.SpringWeb项目

普通的spring项目获取bean可以通过:

ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml")
context.getBean("beanname");

获取ioc容器中的bean
我们可以在main函数中获取一次就够了,因为main函数是java程序的入口,但是springweb项目没有统一的程序入口
思路:在tomcat加载时,把ioc容器进行加载。所以可以使用springweb.jar提供的监听器可以实现

1.首先需要在web.xml里告诉tomcat你的applicationContext的位置:
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:beans.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
2.在servlet里获取bean:
ApplicationContext context =WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletConetxt());
context.getBean("beanname");

因为有两个不同的容器,一个是IOC容器,一个是WEB容器,如果不进行配置,他们彼此不能拿到彼此的东西,使用上面的方法可以在WEB容器拿到ioc容器内实例化的东西;