https://www.cnblogs.com/eaglelihh/p/13340749.html
DataSourceUtils源码分析
https://www.cnblogs.com/wt20/p/10958238.html
1、Spring
1.Spring
Spring是一个开源的JAVA EE框架,使得JAVA EE应用程序开发更加简便,提供了功能强大的IOC容器,
并支持声明式事务和AOP编程。
优点:
1.解耦、简化开发
2.支持声明式事务
3.支持AOP编程
2.构建一个Spring应用
1.maven导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
spring-core:
Spring框架基本的核心工具类,Spring其它组件要都要使用到这个包里的类,是其它组件的基本核心。
spring-beans:
所有应用都要用到的,它包含访问配置文件、创建和管理bean。
spring-context:
Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持。
package org.nt.ldd.service;
public interface UserServer {
void add();
}
package org.nt.ldd.service.impl;
import org.nt.ldd.service.UserServer;
public class UserServiceImpl implements UserServer {
@Override
public void add() {
System.out.println("添加方法");
}
}
<?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="userService" class="org.nt.ldd.service.impl.UserServiceImpl" scope="singleton"></bean>
</beans>
package org.nt.ldd;
import org.junit.Test;
import org.nt.ldd.bean.User;
import org.nt.ldd.service.UserServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
@Test
public void applicationContext() throws Exception{
/**
* maven项目的系统根目录默认是src/main/java和src/main/resources,而不是src,
* 所以beans.xml文件必须放到src/main/java和src/main/resources下面的文件夹或者包中。
*/
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserServer userServer = (UserServer) applicationContext.getBean("userService");
userServer.add();
}
}
3、SpringBean作用域
① singleton
使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。
② prototype
使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。
③ request
该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于
WebApplicationContext环境。
④ session
该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。
⑤ global-session
该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。
4、SpringIOC容器创建对象
IOC(控制反转):
Bean不再交给程序自己去创建和配置,而是交给IOC容器进行管理。
将程序创建Bean的控制权,交给了IOC容器,这就是控制反转。
DI(依赖注入):
在Spring框架创建Bean对象时,动态的将依赖对象注入到Bean组件中。
原理:反射机制+Dmo4j解析XML配置。
dom4j解析XML文件,使用BeanId查找bean是否存在,存在获取该bean的class地址,使用放射机制初始化Bean。
BeanFactory Bean抽象工厂类。
1.IOC创建对象, 几种方式?
1) 调用无参数构造器
<bean id="user1" class="com.ldd.entity.User" />
2) 带参数构造器
<bean id="user2" class="com.ldd.entity.User">
<constructor-arg name="name" type="java.lang.String" value="张三"></constructor-arg>
<constructor-arg name="age" type="java.lang.Integer" value="18"></constructor-arg>
</bean>
3) 工厂创建对象
<bean id="factory" class="com.ldd.entity.ObjectFactory"></bean>
<!-- 通过实例工厂方法创建 -->
<bean id="user3" factory-bean="factory" factory-method="getInstance"></bean>
<!-- 通过静态工厂方法创建 -->
<bean id="user4" class="com.ldd.entity.ObjectFactory" factory-method="getStaticInstance"></bean>
5、IOC依赖注入几种方式
1) 通过构造函数
<bean id="userDao" class="cn.ldd.UserDao"></bean>
<!-- service instance -->
<bean id="userService" class="cn.ldd.UserService">
<constructor-arg ref="userDao"></constructor-arg>
</bean>
2) 通过set方法给属性注入值
<bean id="userDao" class="cn.ldd.UserDao"></bean>
<!-- service instance -->
<bean id="userService" class="cn.ldd.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
3) p名称空间
注意:spring3.0以上版本才支持
<beans
....
....
xmlns:p="http://www.springframework.org/schema/p"
<bean id="userDao" class="cn.ldd.UserDao"></bean>
<bean id="userService" class="cn.ldd.UserService" p:userDao-ref="userDao"></bean>
<bean id="userAction" class="cn.ldd.UserAction" p:userService-ref="userService"></bean>
4) 注解
开启注解扫描
<context:annotation-config/>
<context:component-scan base-package="com.ldd"></context:component-scan>
@Component 指定把一个对象加入IOC容器
<bean class="">
@Component("id")
<bean id="" class="">
@Repository 作用同@Component; 在持久层使用
@Service 作用同@Component; 在业务逻辑层使用
@Controller 作用同@Component; 在控制层使用
#设置Bean作用域
@Scope("prototype")
public class User {
...
...
#init-method
@PostConstruct
public void myInit(){
System.out.println("init-method");
}
#destroy-method
@PreDestroy
public void myDestroy(){
System.out.println("destroy-method");
}
@Resource与@Autowired区别?
@Autowired与@Resource都可以用来装配bean. 都可以写在属性上,或写在setter方法上。
@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,
如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果
我们想使用名称装配可以结合@Qualifier注解进行使用:
@Autowired() @Qualifier("baseDao")
private BaseDao baseDao;
@Resource(这个注解属于J2EE的 jdk1.6提供的),默认按照名称进行装配,名称可以通过name属性进行指定,
如果没有指定name属性,当注解写在属性上时,默认取属性名进行按照名称查找,如果注解写在setter
方法上默认取方法属性名进行装配。 当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意
的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource(name="baseDao")
private BaseDao baseDao;
6、Bean属性集合注入
1.List
package org.nt.ldd.bean;
import java.util.List;
public class User {
private List<String> list;
public User() { }
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
}
<bean id="user" class="org.nt.ldd.bean.User">
<property name="list">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</list>
</property>
</bean>
2.Set
package org.nt.ldd.bean;
import java.util.Set;
public class User {
private Set<String> set;
public User() { }
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
}
<bean id="user" class="org.nt.ldd.bean.User">
<property name="set">
<set>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</set>
</property>
</bean>
3.Map
package org.nt.ldd.bean;
import java.util.Map;
public class User {
private Map<String,Object> map;
public User() { }
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
}
<bean id="user" class="org.nt.ldd.bean.User">
<property name="map">
<map>
<entry key="zs" value="张三"></entry>
<entry key="ls" value="李四"></entry>
</map>
</property>
</bean>
4.Properties
package org.nt.ldd.bean;
import java.util.Properties;
public class User {
private Properties properties;
public User() { }
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
<bean id="user" class="org.nt.ldd.bean.User">
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>
5.数组
package org.nt.ldd.bean;
public class User {
private String[] strs;
public User() { }
public String[] getStrs() {
return strs;
}
public void setStrs(String[] strs) {
this.strs = strs;
}
}
<bean id="user" class="org.nt.ldd.bean.User">
<property name="strs">
<array>
<value>小倪</value>
<value>同志</value>
</array>
</property>
</bean>
7、静态代理和动态代理
静态代理:
静态代理的实现比较简单,代理类实现与目标对象相同的接口,并在类中维护一个代理对象。通过构造器传入目标对象,赋值给代理对象,进而执行代理对象实现的接口方法,并实现前拦截,后拦截等所需的业务功能。
AspectJ
编程代理
动态代理:
代理对象的生成,是利用JDKAPI, 动态的在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型)
JDK中生成代理对象的API:
Proxy JDK提供的代理对象
static Object newProxyInstance(
ClassLoader loader, 指定当前目标对象使用类加载器
Class<?>[] interfaces, 目标对象实现的接口的类型
InvocationHandler h 事件处理器
)
静态代理与动态代理的区别主要在:
静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件。
动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,
并加载到JVM中
8、Spring事务
1.Spring事务
spring-tx.jar依赖包
PlatformTransactionManager:
平台事务管理器,spring要管理事务,必须使用事务管理器,进行事务配置时,必须配置事务管理器。
TransactionDefinition:
事务详情(事务定义、事务属性),spring用于确定事务具体详情。
TransactionStatus:
事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。
spring底层根据状态进行相应操作。
注意:Spring框架使用TransactionTemplate 需要配置事务管理器。而SpringBoot自动会注入事务
管理器。 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入
DataSourceTransactionManager 实例。如果你添加的是 spring-boot-starter-data-jpa 依赖,框架会
默认注入 JpaTransactionManager 实例。
Spring事务是基于底层数据库本身的事务处理机制实现的,在业务代码中进行事务管理。
2.Spring事务分类:
编程式事务(手动控制事务):
自己手动控制事务,就叫做编程式事务控制。使用TransactionTemplate或者直接使用
PlatformTransactionManager,对于编程式事务管理,
Spring推荐使用TransactionTemplate。比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚。
声明式事务:
声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个
事务,执行完目标方法之后根据执行的情况提交或者回滚。
具体实现:在配置文件中做相关的事务规则声明或者通过注解的方式实现。
优缺点:
声明式事务管理的粒度是方法级别,而编程式事务管理是可以到代码块的级别的。
声明式事务减少代码的冗余,编程式事务开发工作量大。
9、编程式事务
TransactionTemplate(模板事务)
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TransactionTemplate transactionTemplate;
@Override
public void addUser() {
/**
* new TransactionCallback<Object>() 具有返回值
* new TransactionCallbackWithoutResult() 无返回值
*/
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
jdbcTemplate.execute("insert into p_user values('2','张三')");
int i = 1/0;
}
});
}
10、声明式事务
注意:使用声明式事务时,不要在业务逻辑层使用try,否则AOP的异常通知将拦截不到异常。
@Override
public void addUser() {
try {
jdbcTemplate.execute("insert into p_user values('4','张三')");
int i = 1 / 0;
}catch (Exception e){
e.printStackTrace();
}
}
@AfterThrowing("onPointcut()")
public void onAfterThrowing(){
System.out.println("异常通知");
}
1.声明式事务
原理:AOP编程+环绕通知+异常通知
@Autowired
private TransactionTemplate transactionTemplate;
PlatformTransactionManager transactionManager;
TransactionStatus transaction;
@AfterThrowing("onPointcut()")
public void onAfterThrowing(){
System.out.println("异常通知");
//回滚事务
transactionManager.rollback(transaction);
}
@Around("onPointcut()")
public void onAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//开启事务
transactionManager = transactionTemplate.getTransactionManager();
transaction = transactionManager.getTransaction(new DefaultTransactionDefinition());
System.out.println("环绕前");
proceedingJoinPoint.proceed();
System.out.println("环绕后");
//提交事务
transactionManager.commit(transaction);
}
11、Spring事务传播行为
1.传播行为
Spring默认事务传播行为:PROPAGATION_REQUIRED
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务,最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起, 两个事务之间没有关系。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
@GetMapping("update")
//@Transactional 添加事务 一般注解使用在Service层. 默认值:Propagation.REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void update(){}
12、SpringBean生命周期
1.Spring对Bean实例化(相当于new 操作 通过反射机制)。
2.初始化Bean属性。
3.如果bean实现了BeanNameAware接口,spring将bean的id传给setBeanName()方法。
4.如果bean实现了BeanFactoryAware接口,spring将调用setBeanFactory方法,将BeanFactory实例
传进来。
5.如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用
上下文的引用传入到bean中。
6.如果bean实现了BeanPostProcessor接口,它的postProcessBeforeInitialization预初始化方法将被调用。
(作用是在Bean实例创建成功后对其进行增强处理,如对Bean进行修改,增加某个功能 AOP)
7.如果bean实现了InitializingBean接口,spring将调用它的afterPropertiesSet接口方法。
8.调用<bean init-method="init"> 指定初始化方法 init
9.如果bean实现了BeanPostProcessor接口,它的postProcessAfterInitialization接口方法将被调用。
10.若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。同样的,如果bean使用了
destroy-method属性声明了销毁方法,则该方法被调用;
11.调用<bean destroy-method="customerDestroy"> 指定销毁方法 customerDestroy
13、AOP
1.AOP
面向切面编程,通过预编译方式或运行期间动态代理方式,来实现对程序中某些功能一个增强。
SpringAop使用动态代理方式的,在运行期间通过代理方式向目标类织入增强代码。
应用场景:
事务管理、日志记录、方法耗时统计、安全检查等。
2.AspectJ
AspectJ是一个基于Java语言的AOP框架
Spring2.0以后新增了对AspectJ切点表达式支持
@AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
SpringAop是动态代理实现的:
需要代理的类实现了接口的话,采用JDK动态代理实现的,JDK提供了一个Proxy代理对象,创建代理对象,然后将接口
的方法交给InvocationHandler完成。
对类代理的话:通过CgLib动态代理实现的,采用ASM字节码生成代理类的。但是不能对声明为final的方法
进行代理,因为CgLib原理是动态生成被代理类的子类。
专业术语:
目标(target)
被通知的对象,也就是需要加入额外代码的对象。
通知(Advice)
增加的逻辑代码,如日志、安全校验、事务等。
before(前置通知): 在方法开始执行前执行
after(后置通知): 在方法执行后执行
afterReturning(返回后通知): 在方法返回后执行
afterThrowing(异常通知): 在抛出异常时执行
around(环绕通知): 在方法执行前和执行后都会执行
around > before > around > after > afterReturning
连接点(JoinPoint)
可以使用通知的方法。
切入点(Pointcut)
筛选出的连接点,具体使用通知的方法。
切面(Aspect)
通知和切入点的结合,通知和切入点共同定义了切面的全部内容,它是干什么的,什么时候在哪执行。
织入(weaving)
把切面应用到目标对象来创建新的代理对象的过程。
1.JDK代理
动态代理:
定义一个接口Hello,但是我们并不去编写实现类,而是直接通过JDK提供的一个
Proxy.newProxyInstance()创建了一个Hello接口对象。这种没有实现类但是在运行期动态创建了一个接口
对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。
通过Proxy在内存中生成一个代理对象,通过代理对象代理需要被代理的类。
package org.nt.ldd;
import org.nt.ldd.service.UserService;
import org.nt.ldd.service.impl.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUserService {
public static void main(String[] args) {
//创建一个需要代理的实例
final UserService userService = new UserServiceImpl();
//通过Proxy 动态生成一个userService接口的实例
UserService userServiceProxy = (UserService) Proxy.newProxyInstance(ProxyUserService.class.getClassLoader(),
userService.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("~~~~~Hello~~~~~~");
//在动态生成的userService实例方法中,调用需要被代理实例方法
Object invoke = method.invoke(userService, args);
System.out.println("~~~~~World~~~~~~");
return invoke;
}
});
userServiceProxy.add();
}
}
2.Cglib
Cglib可以为类和接口动态创建一个代理对象。
package org.nt.ldd;
import org.nt.ldd.service.OrderService;
import org.nt.ldd.service.UserService;
import org.nt.ldd.service.impl.UserServiceImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ProxyUserService {
public static void main(String[] args) {
//被代理目标对象
final OrderService orderService = new OrderService();
//被代理接口实现类目标对象
final UserService userService = new UserServiceImpl();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(userService.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("~~~~~~Hello~~~~~~");
//Object invoke = method.invoke(userService, objects);
//等同上面代码的效果
Object invoke = methodProxy.invokeSuper(o, args);
System.out.println("~~~~~~World~~~~~~");
return invoke;
}
});
UserService userService1 = (UserService) enhancer.create();
userService1.add();
}
}
13、配置文件AOP动态代理
1.导入jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
package org.nt.ldd.ascpect;
/**
* 切面类
*/
public class MyAscpect{
public void onBefore(){
System.out.println("前置通知");
}
public void onAfter(){
System.out.println("后置通知");
}
}
<!-- 切面类-->
<bean id="myAscpect" class="org.nt.ldd.ascpect.MyAscpect"></bean>
<aop:config>
<!-- 切入点-->
<aop:pointcut id="myPointcut" expression="execution(* org.nt.ldd.service.*.*(..))"/>
<!-- 配置切入点使用的切面-->
<aop:aspect ref="myAscpect">
<aop:before method="onBefore" pointcut-ref="myPointcut"></aop:before>
<aop:after method="onAfter" pointcut-ref="myPointcut"></aop:after>
</aop:aspect>
</aop:config>