1.Spring技术产生的意义
Spring是为了解决业务层和其他各层之间的耦合问题
2.Spring是如何解决耦合问题
(1)IOC:控制反转–帮助我们创建对象
(2)AOP:面向切面–提高代码的扩展性
(3)TX:声明式事务–事务管理
3.SpringIOC
A:SpringIOC的好处
实现了各层之间的解耦
B:IOC:控制反转解释
控制:指的是Spring创建对象的过程
反转:创建对象的这个操作本身时程序员完成的,现在反交给SpringIOC进行创建。
C:具体步骤
-
导包
-
编写applicationContext.xml文件,编写java类
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="stu" class="com.lc.spring.Student"></bean>
</beans>
- 解析xml调用对象
public class Test {
public static void main(String[] args) {
//[1]解析xml文件
ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
//[2]获得对象
Student stu1 = app.getBean("stu", Student.class);
stu1.eat();
}
}
通过这几段简单的代码,我们可以发现我们只需要编写applicationContext.xml这个配置文件,在这个配置文件里面用一个beans标签就可以把一个类的对象创建出来了(再也不用通过new来创建对象了),然后在测试类中通过ApplicationContext来解析xml就可以获取到这个对象里面的方法了。
4.IOC实现的方式
- 使用无参构造器
- 使用有参构造器
- 使用工厂模式
【1】使用无参构造器
<bean id="stu2" class="com.lc.spring.Student"></bean>
[2]使用有参构造
注意
[1]name属性和形参的名称保持一致的
[2]形参的顺序不用和标签的顺序一致
[3]使用name属性进行调用
但是除了name属性还有index(从0)
type :数据类型
建议三者都写上即可
<bean id="stu3" class="com.lc.spring.Student">
<constructor-arg name="a" value="18"></constructor-arg>
<constructor-arg name="name" value="zs"></constructor-arg>
<constructor-arg name="sex" value="男"></constructor-arg>
</bean>
[3]工厂模式
设计模式:设计模式是为了解决某一类问题的产生
(1)首先创建一个接口
public interface people{
public void eat();
public void run();
}
(2)然后让学生类和教师类分别实现这个接口
(3)编写一个工厂类
public class factory{
public People getInstence(String param){
if("stu".equals(param)){
return new Student();
}else if("tea".equals(params)){
return new Teacher();
}
}
}
(4)使用工厂模式进行创建对象
<bean id="factory" class="com.lc.spring.Factory"></bean>
<bean id="be" factory-bean="factory" factory-method="getInstance">
<constructor-arg name="param" value="stu"></constructor-arg>
</bean>
<bean id="be2" class="com.lc.spring3.Factory" factory-method="getInstance2">
<constructor-arg name="param" value="stu"></constructor-arg>
</bean>
这样我们就可以批量创建一类事物的对象了
5.Spring中的DI
DI:依赖注入
作用:给创建好的对象中的全局的属性或者对象进行赋值的操作
依赖注入的方式
- 使用set方法
- 使用有参构造器
- 自动注入
使用set方法注意事项:
(1)name:对象的属性名
(2)value和ref的使用场景
value: 如果注入的属性类型是基本数据类型(包含String)使用value
ref:如果注入的属性类型是对象这个时候使用ref
对于其他两种注入没有什么特别要注意的地方。
DI注入的应用场景例如我们可以在xml中直接使用DI进行数据库连接的配置
DI其他类型值的注入
A、基本类型(String)
B、对象类型
C、数组
D、List
E、set
F、Map
<bean id="us" class="com.lc.spring.User">
<property name="map">
<map>
<entry>
<key><value>A</value></key>
<value>1</value>
</entry>
<entry>
<key><value>B</value></key>
<value>1</value>
</entry>
<entry>
<key><value>C</value></key>
<value>1</value>
</entry>
</map>
</property>
</bean>
6.SpringAOP
A.Aop:提升代码的扩展性,解耦
B.中文含义:面向切面编程
C.通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
D.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
E.使用AOP只需要知道以下几点即可
- 切点:在执行的每一个方法都可以看作是一个切点
- 通知:就是我们需要扩展的功能代码
在切点之前增加的通知称之为前置通知
在切点之后增加的通知称之为后置通知
在切点之前和切点之后都增加的通知称之为环绕通知
在切点代码中有异常会执行的通知称之为异常通知 - 切面:有了切点+通知就可以织成切面
F.Aop实现的方式
(1) Schema base
(2) AspectJ
7.Aop具体实现步骤
(1)Schema base方式实现
[1]导入jar包
aopalliance.jar
aspectjweaver.jar
commons-logging-1.1.3.jar
spring-aop-4.1.6.RELEASE.jar
spring-aspects-4.1.6.RELEASE.jar
spring-beans-4.1.6.RELEASE.jar
spring-context-4.1.6.RELEASE.jar
spring-core-4.1.6.RELEASE.jar
spring-expression-4.1.6.RELEASE.jar
[2]书写通知
前置通知 实现:MethodBeforeAdvice
后置通知 实现:AfterReturningAdvice
[3]确定切点位置
[4]配置需要给哪一个切点加什么样的通知
<!--创建user 的bean类 -->
<bean id="us" class="com.lc.pojo.User"></bean>
<!--声明前置通知的bean对象 -->
<bean id="befor" class="com.lc.pojo.BeforAdvice"></bean>
<!--声明后置通知的bean对象 -->
<bean id="after" class="com.lc.pojo.AfterAdvice"></bean>
<aop:config>
<!--配置切点 -->
<aop:pointcut expression="execution(* com.lc.pojo.User.b())" id="u1"/>
<!--配置通知 -->
<aop:advisor advice-ref="befor" pointcut-ref="u1"/>
<aop:advisor advice-ref="after" pointcut-ref="u1"/>
</aop:config>
注意:
AOP的底层默认的使用是JDK代理 我们也可以手动的开始CGLib代理方式
<!-- cglib代理方式 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
(2)Aspect J方式实现
[1]我们目前使用AOP的不足?
我们目前使用的schema Baes 实现的方式,发现了每一个通知都需要实现对应的接口,每一个接口中就是一个方法,这样的书写方式比较的麻烦的,我们想所有的方法都在一个类中书写就比较方便了。
[2]解决方式
Aspect J方式实现
public class AspectJAdvice {
//前置通知方法
public void beforAd(JoinPoint joinPoint){
System.out.println("前置通知");
}
//后置通知方法
public void afterAd(){
System.out.println("后置通知");
}
//环绕通知方法
public Object aroundAd(ProceedingJoinPoint point) throws Throwable{
System.out.println("环绕通知--前");
Object o = point.proceed();
System.out.println("环绕通知--后");
return o;
}
//异常通知方法
public void throwsAd(){
System.out.println("异常通知");
}
}
<bean id="us" class="com.lc.pojo.User"></bean>
<!--配置通知类的对象-->
<bean id="aps" class="com.lc.advice.AspectJAdvice"></bean>
<aop:config>
<aop:aspect ref="aps">
<aop:pointcut id="pt" expression="execution(* com.lc.pojo.User.a())"></aop:pointcut>
<!--给切点增加对应的通知-->
<aop:before method="beforAd" pointcut-ref="pt"></aop:before>
<!--无论切点中方法是否有异常,这个后置通知都会执行-->
<aop:after method="afterAd" pointcut-ref="pt"></aop:after>
<!--只有切点中的方法没有异常的时候才会执行这个通知-->
<!--<aop:after-returning method="afterAd" pointcut-ref="pt"></aop:after-returning>
<aop:around method="aroundAd" pointcut-ref="pt"></aop:around>
<aop:after-throwing method="throwsAd" pointcut-ref="pt"></aop:after-throwing>
</aop:aspect>
</aop:config>
我们发现 Aspect J的方式虽然可以把所有的通知都结合到一起,书写方便,但是获得切点中的参数和切点所在的类的时候比较的繁琐
[3]两种方式的使用场景
A、schema base :如果我们需要使用切点中的参数或者切点所在的类对象的时候
B、aspect J:就是简单的给切点增加通知的时候使用这个方式比较简单
8.TX声明式事务管理
【1】事务管理的分类
编程式事务:整个事务管理都是需要程序员自己手动编写,自己提交或者回滚
声明式事务:就是整个事务的管理操作,不需要我们自己书写,现在Spring已经帮你处理好了,我们自己只要代码中声明配置即可。
【2】事务使用的场景
当我们执行的式两条或者两条以上的添加、修改、删除的时候才使用事务
【3】使用Spring 中声明式事务
给方法增加事务 我们可以理解为就是给切点增加通知
切点:需要的方法
通知:事务
构成切面
【4】使用的时候需要注意
我们增加事务的代码块不可以自己捕获异常,如果自己进行了异常的捕获,spring就没有办法得知此事的异常,这个时候我们配置的声明式事务就不再起作用
如果我们就需要书写try catch 还要结合声明式事务,这个时候就需要自己手动抛异常
【5】代码实现
<!-- 配置好数据库的连接 -->
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/car?useUnicode=true&characterEncoding=UTF8"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--声明事务的对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"></property>
</bean>
<tx:advice id="ad" transaction-manager="transactionManager">
<tx:attributes>
<!--需要增加事务的方法名-->
<tx:method name="login" />
</tx:attributes>
</tx:advice>
<!--通过配置切面的方式增加通知-->
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.lc.service.impl.AdminServiceImpl.*(..))"></aop:pointcut>
<aop:advisor advice-ref="ad" pointcut-ref="pt"></aop:advisor>
</aop:config>
9.Spring中也是支持属性文件的读取操作
读取属性文件
<context:property-placeholder location="classpath:jdbc.properties"/>
10.Spring的常见注解及其作用
- @Component 创建类对象,相当于配置
bean的ID默认为类名首字母小写,也可以指定ID,例如@Component(“stu”) - @Service 与@Component功能相同.
2.1 写在ServiceImpl类上. - @Repository 与@Component功能相同.
3.1 写在数据访问层类上. - @Controller 与@Component功能相同.
4.1 写在控制器类上. - @Resource(不需要写对象的get/set)
5.1 java中的注解
5.2 默认按照byName注入,如果没有名称对象,按照byType注入
5.2.1 建议把对象名称和spring容器中对象名相同 - @Autowired(不需要写对象的get/set)
6.1 spring的注解
6.2 默认按照byType注入. - @Value() 获取properties文件中内容
- @Pointcut() 定义切点
- @Aspect() 定义切面类
- @Before() 前置通知
- @After 后置通知
- @AfterReturning 后置通知,必须切点正确执行
- @AfterThrowing 异常通知
- @Arround 环绕通知
注意:使用注解,一定要在配置文件中声明注解扫描
<context:component-scan base-package="包名路径"></context:component-scan>