Spring

1.什么是spring?

创建对象设置属性的容器框架(装对象的对象,存在存入,取出等操作)

2.为什么要使用spring?

1.解决代码耦合度高的问题
2.事务繁琐
3.第三方框架运用麻烦
优势:
Spring 除了不能帮我们写业务逻辑,其余的几乎什么都能帮助我们简化开发。
Spring 能帮我们低侵入/低耦合地根据配置文件创建及组装对象之间的依赖关系。IoC
Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制等。AOP
Spring 能非常简单的且强大的声明式事务管理。AOP TX
Spring 提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,且自己也提供了一套 JDBC 模板来方便数据库访问。
Spring 提供与第三方 Web(如 Struts1/2、JSF)框架无缝集成,且自己也提供了一套 Spring MVC 框架,来方便 Web 层搭建。 SSM
Spring 能方便的与如 Java Mail、任务调度、缓存框架等技术整合,降低开发难度。

3.如何使用:

IoC与Spring的关系:
IoC(控制反转)是一种思想,spring实现IoC思想,创建对象,设置属性
控制反转:把创建对象的控制权反转给了 Spring 框架
DI:依赖注入(强调的设置属性)
指 Spring 创建对象的过程中,将对象依赖属性(常量,对象,集合)通过配置设值给该对象。
<bean id=“名字唯一规范” class=“类权限定名” [scope 默认不配置就是单列的] [init-method=“初始化方法” destory-method=“销毁方法” 连接池才会这么配置]>
<property name=“属性名” value=“值” | ref=“bean id 值”/>
<property name=“属性名1” value="值1 | ref=“bean id 值”/>

1.简单使用:

1.入门
0.添加依赖
  <dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-test</artifactId>
		<version>5.0.8.RELEASE</version>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>5.0.8.RELEASE</version>
	</dependency>
1.创建xx类,提供setter方法
2.编写配置文件(导入约束头)
<bean id="hello" class="com.champion.spring.hello.Hello">// id : 当前bean的名字,唯一性 
//class: 当前bean所关联的实体类的全限定名,需要spring创建的对象的全限定名
	<property name="name" value="spring"/>//xxx.setName("spring")
 //property 属性,实体类中的属性//name:属性名,相当于调用setter方法//value:值
 </bean>
3.测试

测试时使用注解方式:
1.启动spring测试,会启动spring容器
@RunWith(SpringJUnit4ClassRunner.class)

2.启动spring容器会加载配置文件(必须加上classpath:)
@ContextConfiguration(“classpath:applicationContext.xml”)

3.添加一个字段(@Autowired注解会从spring容器中取出相应类型(Hello)的bean注入到该字段上)
@Autowired
private Hello hello;

4.最后只需要调用该类中的方法即可(对象spring已经帮我们创建好了)

2.bean的四种实例化方式

1.构造方法
2.静态工厂方法
3.工厂方法
4.实现 FactoryBean 接口实例化
①定义一个xx类
②定义一个 FactoryBean类 实现 FactoryBean的接口,并且覆写其中的方法(1.返回xx类对象 2.xx类对象的字节码)
public class CatBeanFactory implements FactoryBean{
public Cat getObject() throws Exception {
return new Cat();
}
public Class<?> getObjectType() {
return Cat.class;
}
}

③配置文件中:spring解析class时发先这个类实现了FactoryBean这个接口,就会调用 getObject() 方法创建 bean 对象。

④注意若配置类是实现 FactoryBean 接口, 创建类型要去类里面看下

3.bean的作用域()

scope:
singleton:默认方式,此时容器里的bean是单例的,容器中只有一个该bean对象,在spring容器启动时就创建
prototype:多例的,spring容器启动时不会创建对象,只有当使用的时候才会创建,每次创建的都是不同对象,容器只负责创建对象和执行初始化方法,
这个对象不会被spring存起来,用户自己处理,容器不会执行销毁方法.

4.bean的初始化和销毁(注意作用域是单例还是多例的)
<bean id="myDataSurce" class="com.champion.spring.ioc.MyDataSource" init-method="init" destroy-method="destroy"/>
5.DI(依赖注入)

1.构造器注入
2.setter方法注入

<bean id="employee" class="com.champion.spring.di.Employee">
		<property name="id" value="1"/>
		<property name="name" value="崔丝塔娜"/>
	</bean>

3.注入bean(将一个bean通过setter设置给另外一个bean) ref:

<bean id="employee" class="com.champion.spring.di.Employee">
		<property name="id" value="1"/>
		<property name="name" value="崔丝塔娜"/>
	</bean>
	<bean id="department" class="com.champion.spring.di.Department">
	<property name="employee" ref="employee"/>//ref:被设置bean的名字//id name:属性名
	<property name="deptName" value="小卖部"/>
	</bean>

4.注入集合

6.模拟用户注册

测试时需要使用service:
@Autowired
private IUserService userService;

service调用的dao实现类对象,把dao对象作为属性设置给service–>UserServiceImpl (好让框架知道创建什么对象)

private IUserDAO userDAO;
	public void setUserDAO(IUserDAO userDAO){
		this.userDAO=userDAO;
	}

dao中使用了连接池对象:把连接池对象作为属性设置给dao–>UserDAOImpl

private DataSource dataSource;
	public void setDataSource(DataSource dataSource){
		this.dataSource=dataSource;
	}

Spring 加载配置 db.properties 文件(需要勾选namesapce中的context,导入约束,不然没有提示)

<context:property-placeholder location="classpath:db.properties"/>

username框架会获取到当前操作系统中的username,所以在db.perproties中给key加上前缀:jdbc. 以示区别

编写bean:dataSource,UserDAO,UserService
为dao注入dataSource
为service注入dao

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="url" value="${jdbc.url}"/>
		<property name="driverClassName" value="${jdbc.driverClassName}"/>
		<property name="username" value="${jdbc.username}"/>
		<property name="password" value="${jdbc.password}"/>
	</bean>
	<bean id="UserDAO" class="com.champion.dao.impl.UserDAOImpl">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	<bean id="UserService" class="com.champion.service.impl.UserServiceImpl">
	<property name="userDAO" ref="UserDAO"/>
	</bean>

2.进阶使用

1.DI注解
注解解决配置繁琐问题:
@Autowired 取代注入bean 贴字段上或者setter方法上
首先按照依赖对象的类型找,若找到,就是用 setter 或者字段直接注入
如果在 Spring 上下文中找到多个匹配的类型,再按照名字去找,若没有匹配报错
可以通过使用 @Qualifier(“other”) 标签来规定依赖对象按照 bean 的 id 和 类型的组合方式去找
@Value 取代注入常量值,贴setter方法
@Resouce 与 @Autowired的作用相同
2.IoC注解
IoC注解:取代
必须配第三方解析器<context:component-scan base-package=“贴了注解的类所在的包”/>才会生效
四个组件的功能是相同的,只是用于标注不同类型的组件。
@Repository:用于标注数据访问组件,即 DAO 组件。
@Service:用于标注业务层组件。
@Controller:用于标注控制层组件(SpringMVC 的 Controller)。
@Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope 贴在类上 与@Component 一起使用 解决下面在配置文件中配置作用域的问题

<bean id="myDataSurce" class="com.champion.spring.ioc.MyDataSource" init-method="init" destroy-method="destroy"/>

@PostConstruct:初始化方法,创建对象后调用
@PreDestroy:销毁方法,容器销毁时执行,如果是多例的(ConfigurableBeanFactory.SCOPE_PROTOTYPE)则不会执行销毁方法,又用户自己处理
spring只负责对这个多例的对象进行创建和初始化,然后就不管了,也不会存入spring容器中

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class DataSource {
	public DataSource() {
		System.out.println("创建dataSource对象");
	}
	@PostConstruct
	public void init() {
		System.out.println("执行初始化方法");
	}
	public void doWork() {
		System.out.println("执行doWork方法");
	}
	@PreDestroy
	public void destroy() {
		System.out.println("执行销毁方法");
	}
}

3.代理
静态代理:
创建代理类,实现真实类的接口
将真实类对象和增强对象作为代理类的成员变量并且提供setter方法
在代理类的覆写方法中调用增强方法和真实对象的方法
配置文件中:将真实类和增强类作为属性设置给代理类

 <bean id="transactionManager" class="com.champion.spring.transaction.TransactionManager"/>
	<bean id="employeeServiceProxy" class="com.champion.spring.proxy.EmployeeServiceProxy">
		<property name="target">
			<bean class="com.champion.spring.service.impl.EmployeeServiceImpl"/>
		</property>
		<property name="transactionManager" ref="transactionManager"/>
	</bean>

优点:
业务类只需要关注业务逻辑本身,保证了业务类的重用性。
把真实对象隐藏起来了,保护真实对象。
缺点:
代理对象的某个接口只服务于某一种类型的对象,也就是为每个真实类创建一个代理类,比如项目还有其他 service 呢。
若需要代理的方法很多,则要为每一种方法都进行代理处理。
若接口增加一个方法,除了所有实现类需要实现这个方法外,代理类也需要实现此方法。
动态代理:
解决静态代理中代理类随着程序增大而膨胀的问题
动态代理类是在程序运行期间由 JVM 通过反射等机制动态的生成的,所以不存在代理类的字节码文件,动态生成字节码对象,代理对象和真实对象的关
系是在程序运行时期才确定的。
有接口:jdk动态代理
无接口:CGLIB或 Javassist 组件

4.AOP
面向切面编程,是一种思想,spring实现了这种思想(给很多类中的方法加功能请使用AOP)
主要解决为多个方法增强功能,即横向的插入

术语:
Joinpoint:连接点,需要被增强的方法 where:去哪里做增强。
Pointcut:切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强。
Advice:增强,当拦截到 Joinpoint 之后,在方法执行的什么时机(when)做什么样(what)的增强。根据时机分为:前置增强、后置增强、异常增
强、最终增强、环绕增强。
Aspect:切面,Pointcut + Advice,去哪些地方 + 在什么时候 + 做什么增强。
Target:被代理的目标对象。
Weaving:织入,把 Advice 加到 Target 上之后,创建出 Proxy 对象的过程。
Proxy:一个类被 AOP 织入增强后,产生的代理类
使用xml实现AOP:(以事务为例) 需要先添加依赖 aspectjweaver
1.新建一个类,此类编写事务方法(需要横向插入的方法,如上图的箭头)
begin(),commit(),rollback()
2.编写配置文件
(1).声明真实类型
(2).声明插入类型
(3).配置切面
①声明切入点
②声明切入方法
begin,commit,rollback

<bean id="employeeServiceImpl" class="com.champion.spring.service.impl.EmployeeServiceImpl"/>
<bean id="transactionManager" class="com.champion.spring.transaction.TransactionManager"/>
	<aop:config>
	<!-- 配置切面 WHERE WHEN WHAT -->
		<aop:aspect ref="transactionManager">
		<!--配置哪些包下的类的哪些方法需要增强  -->
		<aop:pointcut expression="execution(* com.champion.spring.service.impl.*.*(..))" id="txpointcut"/>
		<!-- 声明在方法执行前调用  begin方法-->
			<aop:before method="begin" pointcut-ref="txpointcut"/>
			<!-- 声明在方法执行后调用commit方法 -->
			<aop:after-returning method="commit" pointcut-ref="txpointcut"/>
			<!--声明有异常的时候调用 rollback方法  -->
			<aop:after-throwing method="rollback" pointcut-ref="txpointcut"/>
		</aop:aspect>
	</aop:config>

默认使用jdk的动态代理,如果要使用 CGLIB动态代理

<aop:config expose-proxy="true">//将expose-proxy 的false该为true

3.使用注解开发AOP
配置文件不需要再写与
配置文件只需要声明包扫描器和第三方aop解析器

  <context:component-scan base-package="com.champion.spring" />
	<aop:aspectj-autoproxy />

真实类加上注解(@Repository,@service…等)
切入的类中:
@Component:声明一个组件
@Aspect:声明一个切面
@Pointcut(“execution(* com.champion.spring.service.impl..(…))”) 声明pointcut(贴在方法上,所以创建一个方法 pointcut)
public void txPoint(){}

为其他的增强方法贴上注解:
@Around(“txPoint()”):环绕增强,用于自定义真实类的方法执行前后需要执行的方法,就是在真实类执行前/后自定义方法
@Before(“txPoint()”):方法执行前执行增强方法
@AfterReturning(“txPoint()”):方法执行后执行
@AfterThrowing(“txPoint()”):方法有异常时执行
@After(“txPoint()”):所有方法执行完后最终需要执行的方法
5.增强方式
前置增强(before method):在方法执行前调用增强方法
后置增强(after-returning):在方法执行后调用增强方法
异常增强(after-throwing):在方法排除异常时调用增强方法
最终增强(after):在方法执行后调用增强方法,相当于finally中
环绕增强(around):最强的增强方式,可以方法完成前/后完成自定义方法
ProceedingJoinPoint:JoinPoint 子类,只用于环绕增强中,可以处理被增强方法,作为第一个参数,可以调用真实对象的操作方法,注意这个方法
抛出的异常是 Throwable 类型。

   public void around(ProceedingJoinPoint pjp) {//环绕增强
    		System.out.println("开始了");
    		try {
    			pjp.proceed();//执行真实类型的方法
    			System.out.println("抽支烟抽支烟");
    		} catch (Throwable e) {
    			System.out.println("见鬼了");
    		}finally {
    			System.out.println("结束了");
    		}
    	}

异常增强:

//记录异常信息,在所有业务方法抛出异常的地方打印异常
public void WhirtException(Throwable ex){
		System.out.println(ex.getMessage());
	}

throwing="ex"的参数一定套和方法的形参名一致

<aop:after-throwing method="WhirtException" pointcut-ref="txpointcut" throwing="ex"/>

3.集成
目的
利用各个框架的优势,解决各自擅长的问题,提高开发效率
spring集成mybatis 利用spring IoC DI 帮我们创建mapper对象设置属性等等
spring AOP 解决事务问题
spring对事务的支持体现在哪里?
依赖:spring-jdbc spring-tx
DataSourceManager 配置它的时候注意给它设置数据源
怎么配置事务问题,利用AOP配置事务
DruidDataSource
SqlSessionFactoryBean
MapperScannerConfigurer
DataSourceTransactionManager
配置文件编写(含事务)
1.spring集成mybatis
搭建项目
web.xml 3.0 对应servlet 3.0 对应tomcat7
配置spring配置文件
①配置数据库连接池DruidDataSource
②配置sqlsessionFactoryBean
③配置mapper代理对象(xml:MapperFactoryBean/注解:MapperScannerConfigurer)
④配置业务方法(xml/注解:@Service @AutoWired)
⑤配置事务(xml/注解:DataSourceTransactionManager事务管理器,@Transactional )
从持久层到业务层:
1.数据库连接
连接池给sqlSessionFactory使用(openSession())
配置数据库连接池dataSource
声明db.properties
<context:property-placeholder location=“classpath:db.properties”/>

声明初始化方法和销毁方法
声明四要素

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
		<property name="url" value="${jdbc.url}"/>
		<property name="driverClassName" value="${jdbc.driverClassName}"/>
		<property name="username" value="${jdbc.username}"/>
		<property name="password" value="${jdbc.password}"/>
	</bean>

2.获取连接对象sqlsession
mapper接口代理对象需要通过sqlsession对象获取(给mapper)
sqlSessionFactory 在之前 需要创建sqlSessionFactory 对象,

factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));

然后再获取连接(SqlSessionFactory是创建SqlSession的工厂,SqlSession是MyBatis的关键对象,是执行持久化操作的独享,类似于JDBC中的Connection)

return factory.openSession();//返回连接对象

现在将创建sqlSessionFactory 交给spring,使用配置文件SqlSessionFactoryBean
属性:
关联连接池
mybatis主配置文件(mybatis主配置文件就不再写这些内容,主要写一些mybatis的全局配置)
别名
mapper文件

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!--关联连接池  -->
		<property name="dataSource" ref="dataSource"/>
		<!--  mybatis主配置文件-->
		<property name="configLocation" value="classpath:mybatis-config.xml"/>
		<!-- 别名 -->
		<property name="typeAliasesPackage" value="com.champion.domain"/>
		<!-- 关联mapper文件 --> //可以不配,因为mapper的java文件和xml文件在一起的,找得到
		<property name="mapperLocations" value="classpath:com/champion/mapper/*Mapper.xml"/>
	</bean>

3.获取mapper接口代理对象
业务方法需要调用mapper中的方法(给业务层使用)
在之前,需要获取SqlSession连接对象再去获取mapper接口的代理对象

  SqlSession session=MybatisUtil.getSession();
        		UserMapper userMapper = session.getMapper(UserMapper.class);
                      User user = userMapper.selectUserByUsernameAndPassword(username, password);

使用sqring管理对象:
配置mapper接口代理对象:mapperFactoryBeanbean的id应该为具体mapper的名字
属性:声明引用对象 ref(通过sqlsessionFactory)
属性:mapper接口 value:xxxmapper文件的全限定名

  <bean id="accountMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
	<!-- 指定sqlsessionFactory,获取sqlsession -->
		<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
		<!-- 指定mapper接口,通过动态代理创建对象 -->
		<property name="mapperInterface" value="com.champion.mapper.AccountMapper"/>
	</bean>

可用注解方式替代,需要配置mapper接口扫描器(…MapperScannerConfigurer)

   <!--mapper接口扫描器  -->
                	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                		<property name="basePackage" value="com.champion.mapper"/>//为该包下面所有的mapper接口创建对象,存入容器中
                	</bean>

使用 Mapper 接口扫描器可以批量生成 Mapper 接口代理对象并注册到 Spring 容器中,遍历mapper包下所有的mapper接口再通过反射创建出所有的mapper代理对象,存入容器中

4.配置业务层对象
xml方式:
不使用spring时:自己创建对象

private IEmployeeService service = new EmployeeServiceImpl();

使用spring时:
将创建对象的操作交给spring
业务实现类中需要使用mapper代理类去调用相关方法,业务对象中需要指明引用的哪个mapper对象,让spring去创建

 @Autowired
                    	private AccountMapper accountMapper;

配置文件:
属性: 属性名 (对应上面的accountMapper)ref: 引用的mapper名

  <bean id="accountService" class="com.champion.service.impl.AccountServiceImpl">
                    		<property name="accountMapper" ref="accountMapper"/>
                      </bean>

注解方式:@Service @AutoWired

<context:component-scan base-package="com.champion.service"/> <!--IoC DI 注解解析器  -->

5.配置事务
配置事务管理器 DataSourceTransactionManager
对哪个数据库进行事务管理
属性:属性名(dataSource) ref:引用的数据库连接池名称(dataSource)

                	<bean id="transactionManager"
                		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                		<property name="dataSource" ref="dataSource" /><!-- 对那个数据库进行操作 -->
                	</bean>

事务配置:
xml方式:
配置增强方方法 When what

  <!--配置增强方法    加入 tx 约束头-->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="transfer"/>
		</tx:attributes>
	</tx:advice>

使用AOP 为其加上事务
定义where
关联 where when what

 <!-- 使用AOP 配置事务 -->
	<aop:config>
		<aop:pointcut expression="execution(* com.champion.service.impl.*.*(..))" id="txPointcut"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
	</aop:config>

注解方式:@Transactional (贴类上,表示这个类中的所有方法都需要事务)
事务管理器的id 要为 id=“transactionManager”
不然报错:org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘transactionManager’ available: No matching PlatformTransactionManager bean found for qualifier ‘transactionManager’ - neither qualifier match nor bean name match!

   public void transfer(Long outId, Long inId, BigDecimal amount) {
                        		accountMapper.substractBanlance(outId, amount);
                        		accountMapper.addBalance(inId, amount);
                        	}

方法中有异常,则回滚。(注意:这个事务是MySQL层控制,回滚的操作也是MySQL控制的)
哪里需要事务就贴哪里:spring已经知道哪个包下的哪个类甚至哪个方法需要事务了,不需要再使用过aop去配置事务,如果需要加其他功能,比如日志,再使用aop去做方法增强

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值