Spring框架
1.基本使用
1.1添加依赖
<!-- Spring常用依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
1.2创建配置文件
1.文件命名规则:命名无限制,约定俗成命名有:spring-context.xml、applicationContext.xml、beans.xml
<?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>:JavaBean
id:bean的唯一标识
class:bean全类名
-->
<bean id="userServiceImpl" class="com.lqq.serviceImpl.UserServiceImpl"></bean>
</beans>
1.3测试
1.首先实例化工厂
2.通过工厂实例化对象
3.通过对象调用方法
@Test
public void test1(){
//1.实例化工厂
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:beans.xml");
//2.通过工厂获得实例
//UserServiceImpl userServiceImpl = (UserServiceImpl) ctx.getBean("userServiceImpl");
//不需要强转的实例
UserServiceImpl userServiceImpl = ctx.getBean("userServiceImpl", UserServiceImpl.class);
userServiceImpl.say();
}
2.spring核心思想控制反转IOC
将对象的创建权限转交给spring容器,spring容器为我们创建对象,我们只需要从spring容器中获取实例
3.依赖注入DI
3.1声明的依赖注入
1.在某个Bean中需要实例另一个Bean对象,需要进行依赖注入
public class UserServiceImpl {
//private UserDaoImpl userDao = new UserDaoImpl();
private UserDaoImpl userDao;// 只要声明了对象spring容器会自动创建实例
public void setUserDao(UserDaoImpl userDao) {
this.userDao = userDao;
}
public void addUser(){
System.out.println("UserServiceImpl.addUser");
userDao.addUser();
}
}
<bean id="userService" class="com.lqq.service.impl.UserServiceImpl">
<!--
依赖注入:给userService中的userDao属性赋值
把userDao实例注入到UserService中的userDao属性中,使用set方法
-->
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.lqq.dao.impl.UserDaoImpl"></bean>
3.2一个实例不同数据类型的依赖注入
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
public User(Integer id,String name){
this.id = id;
this.name = name;
}
private Integer id;
private String name;
private List<String> email;
private Set<String> sets;
private Map<String,Object> map;
private String[] arrays;
private Properties properties;
}
<bean id="user" class="com.lqq.entity.User">
<property name="id" value="1"/>
<property name="name" value="鲁千旗"/>
<property name="email" >
<list>
<value>lqq1.com</value>
<value>lqq2.com</value>
<value>lqq3.com</value>
</list>
</property>
<property name="sets">
<set>
<value>A</value>
<value>B</value>
<value>C</value>
</set>
</property>
<property name="map">
<map>
<entry key="lqq" value="鲁千旗"></entry>
<entry key="lqq" value="鲁千旗"></entry>
<entry key="lqq" value="鲁千旗"></entry>
<entry key="userDao" value-ref="userDao"></entry>
</map>
</property>
<property name="arrays">
<array>
<value>1</value>
<value>1</value>
<value>1</value>
</array>
</property>
<property name="properties">
<props>
<prop key="lqq1">lqq1</prop>
<prop key="lqq2">lqq2</prop>
<prop key="lqq3">lqq3</prop>
</props>
</property>
</bean>
3.3spring容器创建对象通过的默认是无参构造方法
通过有参构造方法完成spring容器的对象创建
<bean id="user2" class="com.lqq.entity.User">
<!--
type:根据类型的寻找参数
name:根据构造器形参名寻找
index:根据索引
ref:根据对象
value:文本值
-->
<!-- <constructor-arg name="id" value="10"/>
<constructor-arg name="name" value="lqq"/>-->
<!--<constructor-arg index="0" value="10"/>
<constructor-arg index="1" value="lqq"/>-->
<constructor-arg type="java.lang.Integer" value="10"/>
<constructor-arg type="java.lang.String" value="lqq"/>
</bean>
3.4自动注入autowire
<!--
<bean>:JavaBean
id:bean的唯一标识
class:bean全类名
autowire:自动注入
no:默认关闭
byName:根据名称注入,已被注入属性的名称为准到spring 容器中找,找到注入,找不到不注入
default:根据父标签自动注入
-->
<bean id="userService" class="com.lqq.service.impl.UserServiceImpl" autowire="byName">
<!--<property name="userDao" ref="userDao"></property>-->
</bean>
4.spring容器创建的实例默认是单例的
<!--
Spring默认创建bean是单例的
scope:控制bean是否单例的
singleton:单例默认的
prototype:原生多例的
request:每次请求创建一个bean
session:每个session创建一个bean
-->
<bean id="userService" class="com.lqq.service.impl.UserServiceImpl" scope="prototype"></bean>
5.spring生命周期
<!--
容器创建初始化时调用的方法init-method
销毁容器时调用的方法destroy-method
-->
<bean id="userDao" class="com.lqq.dao.impl.UserDaoImpl" init-method="init" destroy-method="destory"></bean>
单例bean:
随着工厂启动创建==》构造方法==》set方法依赖注入==》init容器初始化方法==》构建完成==》工厂关闭销毁
6.代理设计模式
6.1静态代理
使用静态代理完成,真实事务与系统服务的分离
6.1.1代理类
ublic class UserServiceImplProxy implements UserService {
private LogManager logManager;
private TransactionManager transactionManager;
private UserService userService;
public UserServiceImplProxy(UserService userService,TransactionManager transactionManager,LogManager logManager){
this.userService = userService;
this.logManager = logManager;
this.transactionManager = transactionManager;
}
@Override
public void addUser() {
logManager.start();
transactionManager.start();
userService.addUser();
transactionManager.commit();
logManager.end();
}
}
6.1.2真实事务类
public class UserServiceImpl implements UserService {
//真是业务主体
@Override
public void addUser(){
System.out.println("真实业务主体");
}
}
6.1.3测试效果
public void testAddUserProxy(){
//1.创建系统服务对象
TransactionManager transactionManager = new TransactionManager();
LogManager logManager = new LogManager();
//2.创建真实事务对象
UserService userService = new UserServiceImpl();
//3.创建代理类
UserServiceImplProxy userServiceImplProxy = new UserServiceImplProxy(userService, transactionManager, logManager);
//4.调用方法
userServiceImplProxy.addUser();
}
6.2基于jdk动态代理
由于静态代理每一个真实事务类都需要一个单独的代理所以,我们需要一个公共的代理,通过接口完成动态代理,真实业务必须继承接口
6.2.1创建一个公共的代理类ProxyHandler
public class ProxyHanlder implements InvocationHandler {
//系统服务
private LogManager logManager;
private TransactionManager transactionManager;
private Object target;//这是业务主体
public ProxyHanlder(TransactionManager transactionManager,LogManager logManager,Object object){
this.logManager = logManager;
this.transactionManager = transactionManager;
this.target = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1.系统服务开始
logManager.start();
transactionManager.start();
//2.真实业务主体
Object invoke = method.invoke(target, args);
//3.系统服务收尾
transactionManager.commit();
logManager.end();
return invoke;
}
}
6.2.3测试
public void testAddTeacherProxy(){
//1.创建系统服务对象
TransactionManager transactionManager = new TransactionManager();
LogManager logManager = new LogManager();
//2.创建真实事务对象
TeacherService teacherService = new TeacherServiceImpl();
//3.创建代理类
ClassLoader classLoader = teacherService.getClass().getClassLoader();//真实事务对象的类加载器
Class<?>[] interfaces = teacherService.getClass().getInterfaces();//这是事务的接口
ProxyHanlder proxyHanlder = new ProxyHanlder(transactionManager, logManager, teacherService);//自定义handler
//4.创建代理对象
TeacherService o = (TeacherService) Proxy.newProxyInstance(classLoader, interfaces, proxyHanlder);
//5.调用
o.addTeacher();
}
6.3基于CGlib的动态代理
通过父子关系完成动态代理,真实业务类不需要继承接口
6.3.1创建公共代理类
public class CglibProxyHandler implements InvocationHandler {
private TransactionManager transactionManager;
private LogManager logManager;
private Object target;
public CglibProxyHandler(TransactionManager transactionManager,LogManager logManager,Object target){
this.logManager = logManager;
this.transactionManager =transactionManager;
this.target = target;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
logManager.start();
transactionManager.start();
Object invoke = method.invoke(target, objects);
transactionManager.commit();
logManager.end();
return invoke;
}
}
6.3.2测试
public void testCglibProxy(){
//1.创建系统服务对象
TransactionManager transactionManager = new TransactionManager();
LogManager logManager = new LogManager();
//2.创建真实事务对象
UserServiceImpl userService = new UserServiceImpl();
//3.创建代理类
Enhancer enhancer = new Enhancer();
//为代理类设置父类
enhancer.setSuperclass(UserServiceImpl.class);
//设置自定义的handler,目的是调用系统服务代码
enhancer.setCallback(new CglibProxyHandler(transactionManager,logManager,userService));
//生成代理类对象
UserServiceImpl o = (UserServiceImpl) enhancer.create();
o.addUser();
System.out.println(o.getClass());
}
7.Aop面向切面编程
7.1环境搭建
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
7.2AOP中的术语
7.2.1目标对象
就是真实事务主体
7.2.2增强(通知)
系统服务:前置通知:MethodBeforeAdvice
后置通知:AfterReturningAdvice
环绕通知:MethodInterceptor
异常抛出通知:ThrowsAdvice
前置通知
public class MyBeforeAdvices implements MethodBeforeAdvice {
/**
* 目标对象的目标方法之前调用
* @param method 目标方法
* @param objects 目标方法的参数
* @param o 目标对象
* @throws Throwable
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("方法调用之前");
}
}
后置通知
public class MyBeforeAdvices implements AfterReturningAdvice {
/**
* 目标对象的目标方法之前调用
* @param method 目标方法
* @param objects 目标方法的参数
* @param o 目标对象
* @throws Throwable
*/
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("方法调用之后");
}
}
环绕通知
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("环绕开始");
Object proceed = methodInvocation.proceed();
System.out.println("环绕结束");
return proceed;
}
}
异常抛出
public class MyThrowAdvice implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target, Exception e) throws Throwable {
System.out.println("method=" + method.getName());
System.out.println("抛出异常:" + e.getMessage());
System.out.println("成功回滚事务");
}
}
bean.xml配置
<bean id="userService" class="com.lqq.service.impl.UserServiceImpl"/>
<bean id="myBeforeAdvices" class="com.lqq.advices.MyBeforeAdvices"/>
<bean id="myMethodInterceptor" class="com.lqq.advices.MyMethodInterceptor"/>
<bean id="myMyThrowAdvic" class="com.lqq.advices.MyThrowAdvice"/>
<aop:config>
<!--
只有目标方法能匹配到当前表达式才会创建代理
-->
<!--
1.先匹配表达式
2.通过表达式的id找到对应的advice
3.通过advice调用增强的方法
-->
<aop:pointcut id="p1" expression="execution(* com.lqq.service.UserService.*(..))"/>
<aop:advisor advice-ref="myMethodInterceptor" pointcut-ref="p1"/>
<aop:advisor advice-ref="myMyThrowAdvic" pointcut-ref="p1"/>
</aop:config>
7.2.3连接点
能添加通知的地方
7.2.4切点
真正添加通知的地方
7.2.5织入
将通知和方法添加到代理类中的过程
7.2.6切面
控制通知(增强)的控制范围
8.数据源引入
8.1DaoImpl实现类需要的配置
8.1.1添加依赖
<!--添加JdbcTemplate依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
8.1.2实现dao层的方法
//继承jdbcTempalte不能直接使用,必须要注入数据源
public class AccountDaoImpl extends JdbcTemplate implements AccountDao {
@Override
public void inMoney(String inName, Double money) {
super.update("update t_account set money = money + ? where name=?",money,inName);
}
@Override
public void outMoney(String outName, Double money) {
super.update("update t_account set money = money - ? where name=?",money,outName);
}
}
8.1.3引入数据库连接池和数据库依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
8.1.4创建数据源
<!--创建数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="driverClassName" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
8.1.5引入jdbc属性配置文件
<!--加载属性文件jdbc.xml-->
<context:property-placeholder location="classpath:jdbc.properties"/>
8.1.6daoImpl需要操作数据库所以需要进行属性注入
<!--继承jdbcTempalte不能直接使用,必须要注入数据源-->
<bean id="accountDao" class="com.lqq.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
9.TransactionManager事务管理器
9.1ServiceImpl完成事务管理需要进行的配置
9.1.1添加事务依赖
<!--添加事务相关的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
9.1.2创建事务管理器
<!--定义一个事务管理器,负责事物的提交或者回滚-->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
9.1.3创建一个事务策略
<!--事务的策略
id:唯一标识
transaction-manager:事务管理器
-->
<tx:advice id="txAdvices" transaction-manager="tx">
<!--具体事务属性
name:方法名称,支持通配符
isolation:事务隔离级别
propagation:事务传播属性
read-only:是否只读
-->
<tx:attributes>
<tx:method name="t*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
9.1.4利用aop完成事务策略的引入
<aop:config>
<aop:pointcut id="p1" expression="execution(* com.lqq.service.AccountService.*(..))"/>
<aop:advisor advice-ref="myAfterAdvice" pointcut-ref="p1"/>
<aop:advisor advice-ref="txAdvices" pointcut-ref="p1"/>
</aop:config>
1.创建一个事务管理器
2.创建事务管理策略绑定事务管理器
3.利用aop完成事务管理策略的使用