学习流程
- spring framework (IOC( 控制反转)/ DI(依赖注入) ,jdbc ,aop/sif4j(简单日志记录外观))(单体应用/微服务)
- spring mvc /struts2
- mybatis(国内主流)/hibernate(ORM)(国外主流)
- spring boot(补充)
扩展知识
shiro权限管理
restful风格
中间件(rabbitmq,kafka)跟spring AMQP整合
Tomcat集群session共享
Redis内存数据库
内存数据库(tt)
搭建maven库
引入配置文件
//配置文件后缀.properties
office.properties//配置文件
ResourceBundle bundle=ResourceBundle.getBundle("配置文件名字");//不能加扩展名
String key=bundle.getObject("office")+"";//查找配置文件里面的key值
IOC容器
pom.xml文件 maven项目必备配置文件
https://mvnrepository.com/ maven存储库
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>5.2.2.RELEASE</version>
<type>pom</type>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.5.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
</dependencies>
<!--实例化PPT类的对象-->
<bean id="office" class="com.stone.service.impl.PPT" scope="singleton"></bean>
Class.forName(xxx.xx.xx) 返回的是一个类
- jvm会查找指定路径类的class文件,然后将class文件读入内存,为该类生成一个class对象作为访问类型信息的入口(类型信息是该类的class文件转换成的数据结构,存储在方法区,class对象就是用于访问这个数据结构的,我们可以通过getClass()方法获取class对象,class对象提供的反射功能其实就是基于该数据结构实现的)
- 会为类的类变量分配空间并赋值、执行静态代码块中的内容,也就是对类进行初始化比如我们熟悉的Class.forName(“com.mysql.jdbc.Driver”),就是告诉jvm加载并初始化Driver类,大家可以进到Driver类中查看其源码,核心内容除了其父类的一些静态变量外,就是Driver类本身的静态代码块了,其中执行了DriverManager.registerDriver(new Driver()),这样一句代码,顾名思义,会创建一个驱动对象,然后进行注册
static{
//静态块,只加载一次
}
bean标签:指定要创建的实体类
ID属性:可以为任意值,但是在整个配置文件中唯一
class属性:要实例化类的权限定名
scope属性:范围属性。
什么时候用默认值singleton?什么时候用prototype?
action:用prototype
service/dao:singleton
init-method属性:定义初始化方法
destory-method属性:指定销毁方法
xml文件放在resources文件夹下
DI依赖注入:
普通注入:
set方法同等于property属性,
name属性名
value赋的值
构造器注入:constructcr-arg
postgress数据库 gitlab数据库 gathub数据库 高斯数据库 mycat分布分表
druid连接池
<!-- 使用配置文件 -->
<context:property-placeholder location="classpath:config/db/mysql.properties"/>
//jdbc基本类型 --与数据库类型做匹配
jdbctemplate.update(sql,params,new int[] {Types.CHAR,Types.CHAR,Types.CHAR,Types.DATE});
柔性事务
事务
IOC(控制反转)
搭建IOC环境:beans ,core,context,expression,log4j
bean标签
加载配置文件applicationContext.xml
ApplicationContext context=new ClassPathXmlApplicationContext("applicationBontext.xml");
User user=context.getbean("abc");//实例化
applicationContext.xml
<bean id="" class="" scope="singleton/prototype"></bean>
socpe属性 singleton: 单实例 默认值 配置文件只要一加载 就会创建该实例对象 放在spring容器中 (Map
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JVUhEZiv-1626491360599)(C:\Users\徐志磊\AppData\Roaming\Typora\typora-user-images\image-20200313092426684.png)]
prototype: 多实例**
配置文件只要一加载 不创建该实例对象
当所有人过来要的时候(getBean(“user”)) 才创建该实例对象 放在spring容器中
注意:获取一次 创建一次 放在spring容器中**
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tvWj8nY8-1626491360606)(C:\Users\徐志磊\AppData\Roaming\Typora\typora-user-images\image-20200313092709479.png)]
使用场景:
action:prototype
service/dao:singleton
singleton的对象当spring容器关闭的时候销毁
prototype的对象长时间不用就会自动销毁
init-method属性
init-method:指定初始化方法
destory-method属性
destory-method:指定销毁方法
<bean id="user" class="com.stone.spring01.User" scope="singleton" init-method="aaa" destroy-method="bbb"></bean>
import标签
<import resource="" // <!-- <import resource="applicationBontext2.xml"/>-->
DI:属性的依赖注入
在IOC创建的时候有属性就会DI赋值进去。
DI是在IOC的基础上进行对象的属性注入的
set属性注入:要有set/get方法
property标签:
name:要复制的属性名
value:要赋的值
ref:针对对象类型。 指向spring中bean的id名
这个对象必须要创建好
构造器方式
导入外部文件.properties
导入这个文件需要添加标题头如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
</beans>
context标签
<context:property-placeholder location="classpath:jdbc.properties"/>
数据库整合
applicationContext.xml里面创建IOC容器对象
<!--c3p0-->
<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- DBCP -->
<bean id="dbcp" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
jdbc.property配置文件
//mysql
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/1905db
jdbc.username=root
jdbc.password=
//orcl
#jdbc.driver=com.mysql.jdbc.Driver
#jdbc.url=jdbc:oracle://localhost:3306/hibernate
#jdbc.username=root
#jdbc.password=
//db2
#jdbc.driver=com.mysql.jdbc.Driver
#jdbc.url=jdbc:db2://localhost:3306/hibernate
#jdbc.username=root
#jdbc.password=
测试文件
test.java
//c3p0方式
@Test
public void test(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationBontext.xml");
DataSource ds=(DataSource)context.getBean("c3p0");
try {
Connection con=ds.getConnection();
System.out.println(con);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
spring的IOC注解
第一步,导包,aop
第二部:开启注解扫描器
<context:component-scan base-package="con.stone"></context:component-scan>
@Component(“bean的id值”) 定义在类上 只要定义在了类上
那么注解扫描器只要一扫描到就会创建该类的实例对象 放在spring容器中
spring发布了公告, @Component这个注解不维护了,要维护这个注解下面衍生出的3个注解
@Controller(“bean的id值”) 针对的就是web层
@Service(“bean的id值”) 针对的是service层
@Repository(“bean的id值”) 针对的是dao层
@Value("属性值") 定义在属性字段上 针对的是基本类型和String类型
如果使用了这个注解 该属性的set方法可以省略不写
@Autowired 定义在属性字段上的 针对的是对象类型
如果定义在了那个对象类型的属性身上 会自动去spring容器中找该类型的实例对象给赋值
@Qualifier("userDaoxxx")定义在属性字段上的 指定用该类型的哪个id名称的实例对象
注意: @Qualifier要想使用 必须结合 @Autowired 一起使用
@Resource(name="userDaoxxx")
@Autowired+@Qualifier("userDaoxxx")
了解的注解:
@Scope("singleton"或则prototype) 定义在类上的 指定当前类是单实例还是多实例
@PostConstruct 定义在方法上 配置初始化方法
@PreDestroy 定义在方法上 配置销毁的方法
spring整合Junit
//首先加载xml文件
@ContextConfiguration(value = "classpath:applicationBontext.xml")
//然后加载配置文件
@RunWith(value = SpringJUnit4ClassRunner.class)
public class SpringJunit {
@Autowired
private UserService userService;
@Autowired
private UserDao userDao;
@Test
public void test() {
userService.save();
}
}
AOP面向切面编程
AOP基本概念:
1、连接点(joinpoint):类种的所有方法
2、切入点(pointcut):有共性功能代码的方法
3、通知(Advice):被抽取的共性功能的代码逻辑,通知有位置之分,叫通知类型。前置通知,后置通知
4、引入(Introduction):通知只能抽取逻辑代码,变量是拿不出来的,把变量引入到切点方法中去,就要用引入
5、目标对象(target Object):有切入点的方法的对象
6、AOP代理(AOP Proxy):代理目标对象就叫做AOP代理
7、织入(weaving):代理对象把通知织入到目标对象的切入点方法中,是一个动作
8、切面(Aspect):通知和切入点之间的关系
通知的五种方法
before前置通知,在方法执行之前执行
after后置通知,在方法执行之后执行
afterreturning返回通知,在方法返回结果之后执行
afterthrowing后置异常通知,在方法抛出异常后执行
around环绕通知(proceedingjoinpoint pjp)围绕方法执行,有返回值
pjp.proceed
注解:
@aspect 注解在类上,标注切面类
@before(value=“execution(目标方法)”)注解在方法上,
AOP原理
动态代理:jdk的动态代理
使用jdk额java.lang.reflect.proxy
//创建目标对象
userDao userdao=new userDaoimpl();
//jdk的动态代理,来实现代理上面的userdao对象,并对功能增强
InvocationHandler h=new myInvocationHandle(userdao);
//newProxyInstance三个参数的意思
//1、loader:类加载器,累的字节码对象获得
//2、interfaces得到该对象所有实现接口的字节码对象的数组
//3、需要实现InvocationHandler端口的对象,这步骤需要自己动手实现,对目标对象方法功能的增强就是这个方法中完成的
//返回的是代理对象
Object newProxyInstance =Proxy.newProxyInstance(userdao.getClass().getClassLoader(),userdao.getLcass().getInterfaces(),h);
userDao proxy=(userDao)newProxyInstance;
proxy.add();
private class myInvocationHandle inplements InvocationHandle{
Object obj;
public myInvocationHandle(Object obj){
this.obj=obj;
}
//
@Override
public Object invoke(Object proxy,Method mothod,Object[]args)thorws Thorwable{
Object obj1=mothod.invoke(obj,args)
}
}
cglib代理
配置bean
applicationContext代表IOC容器
ClassPathXmlApplicationContext加载配置文件
FileSystemXmlApplicationContext从文件系统加载配置文件
class:bean的全类名,通过反射的方式在IOC容器中创建bean,要求bean必须有无参数的构造器
id标识容器中的bean。id唯一
scope范围
singleton单实例 ,只要配置文件加载就会创建对象,所有使用都是同一个对象
prototype多实例,配置文件创建,但不会创建对象,只有getbean的时候才会去调用,所有访问都是不同的对象
action:prototype
service/dao:singleton
init-method:指定初始化方法
destory-method:指定销毁方法
import导入外部的配置文件resource外部配置文件的地址
<import resource="xxx.xml">
DI依赖注入
property:是set属性的方式
name:要赋值的属性名
value:要赋的值,针对基本类型
ref:要赋的对象属性,针对对象类型,指向bean的id名
<!-- set注入 -->
<!-- 属性必须要有set方法 -->
<bean id="user" class="spring.com.stone.beans.User" scope="">
<property name="name" value="mary" ></property>
<property name="age" value="12"></property>
</bean>
<!-- 构造器注入 可以指定参数的位置-->
<!-- 必须要有参构造方法-->
<bean id="car" class="spring.com.stone.beans.Car">
<constructor-arg name="brand" value="audi"></constructor-arg>
<constructor-arg name="corp" value="shanghai"></constructor-arg>
<constructor-arg name="price" value="120000"></constructor-arg>
</bean>
复杂属性注入(map,list,[]..属性注入)
<bean id="collBean" class="spring.com.stone.beans.CollBean">
<property name="ss">
<!-- 数组类型 -->
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
<property name="ll">
<!-- list类型 -->
<list>
<value>111</value>
<value>222</value>
<ref bean="car"/>
</list>
</property>
<property name="mm">
<!-- map -->
<map>
<entry key="k1" value="aaa"></entry>
<entry key="k2" value="bbbb"></entry>
<entry key="k3" value-ref="car"></entry>
</map>
</property>
<property name="properties">
<!-- properties类型 -->
<props>
<prop key="hibernate.username">root</prop>
<prop key="hibernate.password">1234</prop>
</props>
</property>
</bean>
整合连接池(c3p0,jdbc...)
@Test //硬编码c3p0
public void test() throws Exception {
// c3p0
ComboPooledDataSource dateSource=new ComboPooledDataSource();
//设置驱动
dateSource.setDriverClass("com.mysql.jdbc.Dricer");
//设置地址
dateSource.setJdbcUrl("jdbc:mysql://localhost:3306/1905db");
//设置用户名
dateSource.setUser("root");
//设置密码
dateSource.setPassword("");
//问连接池要连接对象
Connection con = dateSource.getConnection();
System.out.println(con);
}
@Test //DBCP的硬编码方式
public void test2() throws SQLException
{
BasicDataSource dataSource = new BasicDataSource(); // ioc
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/1905db");
dataSource.setUsername("root");
dataSource.setPassword(""); //di
Connection con = dataSource.getConnection();
System.out.println(con);
}
<!-- 引入配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- c3p0 -->
<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- dbcp -->
<bean id="dbcp" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
IOC控制反转
开始注解扫描器:告诉spring应该去哪个包去解析注解
配置注解组件
半注解:
自己的类用注解,别人的类用xml
常用注解组件:
@Component(“bean的id值”)注解在类上,和创建bean一样
@Controller(“bean的id值”) 针对的是web层
@Service(“bean的id值”)针对的是server层
@Repository(“bean的id值”)针对的是dao层
@value(“xxx”)注解在属性上,给属性赋值
@Autowired注解在对象属性上,自动赋值
@Qualifier("")指定用该类型的那个名称的实例对象,@Qualifier使用必须结合@Autowired
@Resource(name="")可以代替@Autowired和@Qualifier("")
需要了解的注解
@Scope(“singleton"或者"prototype”) 定义在类上,指定当前类是单实例还是多实例
@PostConstruct 定义在方法上 配置初始化方法
@PreDestroy 定义在方法上 配置销毁的方法
//开启注解扫描器
<context:component-scan base-package="spring.com.stone"></context:component-scan>
全注解
需要有一个注解类,不在加载配置文件 而是加载这个注解类
//注解类
@Configuration//注解该类是个配置类
@ComponentScan(basePackages="spring.com.stone")//注解去哪里扫描包
@PropertySource(value = "classpath:jdbc.properties")//注解去哪里加载文件
//注解在注解类上
//别人的类
@Bean(name="c3p0")
//创建c3p0连接池给spring容器
public DataSource createDataSourcec3p0() throws Exception {
ComboPooledDataSource dateSource=new ComboPooledDataSource();
//设置驱动
dateSource.setDriverClass("com.mysql.jdbc.Dricer");
//设置地址
dateSource.setJdbcUrl("jdbc:mysql://localhost:3306/1905db");
//设置用户名
dateSource.setUser("root");
//设置密码
dateSource.setPassword("");
return dateSource;
}
//加载注解类
ApplicationContext context= new AnnotationConfigApplicationContext(springconfig.class);
spring整合Junit
//告诉spring配置文件在哪个地方
@ContextConfiguration(value = "classpath:applicationContext.xml")
//告诉spring谁加载配置文件
@RunWith(value = SpringJUnit4ClassRunner.class)
//注解在测试类上
spring-AOP
<!-- 配置aop -->
<aop:config>
<!-- 配置切面
配置通知与切面之间的关系
要把通知,切入点所在的类配置成spring管理的bean -->
<aop:aspect ref="MyAdice">
<!-- 插入方法before、atfer、after-returning 、after-throwing、around-->
<--method:通知方法名
pointcut:目标方法中的方法
pointcut(切入点表达式) 可以使用通配符使用"*.." 标识任意多个包
参数也可以使用通配符*
.. 代表任意个参数-->
<aop:before method="before" pointcut="execution(public void com.stone.beans.TargetObject.method(int, int))"/>
</aop:aspect>
</aop:config>
<!-- 配置目标对象 -->
<bean id="TargetObject" class="com.stone.beans.TargetObject"></bean>
<!-- 配置通知对象 -->
<bean id="MyAdice" class="com.stone.beans.MyAdice"></bean>
织入
编译期织入
装载时织入
运行时织入 spring属于运行时织入
切入点配置方式
局部切入点:普通就是局部
<aop:aspect ref="MyAdice">
<aop:after method="after" pointcut="execution(public void com.stone.beans.TargetObject.method(int, int))"/>
</aop:aspect>
切面间共享切入点
//定义且面积按共享方法
<aop:pointcut expression="execution(* *..method(..))" id="method"/>
<aop:aspect ref="MyAdice">
<aop:before method="before" pointcut-ref="method"/>
</aop:aspect>
切面内共享切入点
<aop:aspect ref="MyAdice">
<aop:pointcut expression="execution(* *..method(..))" id="method"/>
<aop:before method="before" pointcut-ref="method"/>
<aop:before method="after" pointcut-ref="method"/>
</aop:aspect>
//通知类
public class MyAdice {
//应用于各种校验
public void before() {
System.out.println("before......");
}
//应用于清理现场
public void after() {
System.out.println("after.......");
}
//应用于常规数据处理
public void afterReturning() {
System.out.println("afterReturning...");
}
//应用于包装异常
public void afterthrowing() {
System.out.println("afterthrowing...");
}
/*
*可以做任何事
*在环绕通知时,需要传递一个ProceedingJoinPoint类对象,然后调用proceed()方法
*才会完整执行,否则只会做前置输出,结果和后置通知不会出来
*/
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around...start");
pjp.proceed();
System.out.println("around...end");
}
}
获取匹配方法参数
//通过在方法里传递JoinPoint jp形参
//例
public void before(JoinPoint jp) {
Object[] args=jp.getArgs();
for(int i=0;i<args.length;i++) {
System.out.println(args[i]);
}
System.out.println("before......");
}
获取对象参数
获取返回值
获取通知的返回值。returning=""
throwing=“”
注解aop
/*开启扫描
*创建目标对象和通知bean
*给通知配置切面
*开启aop空间
给通知方法添加注解*/
//通知类
@Component("myAdice")
@Aspect
public class MyAdice {
@Before(value = "execution(* *..method(..))")
public void before(JoinPoint jp) {
Object[] args=jp.getArgs();
for(int i=0;i<args.length;i++) {
System.out.println(args[i]);
}
System.out.println("before......");
}
@After(value = "execution(* *..method(..))")
public void after() {
System.out.println("after.......");
}
public void afterReturning() {
System.out.println("afterReturning...");
}
public void afterthrowing() {
System.out.println("afterthrowing...");
}
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around...start");
pjp.proceed();
System.out.println("around...end");
}
}
//目标对象
@Component("targetObject")
public class TargetObject {
public void method(int i,int j) {
int sub=i+j;
System.out.println(sub);
}
}
//配置文件
<context:component-scan base-package="com.stone"></context:component-scan>
//把aop注解功能打开
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
//测试方法
@Test
public void test() {
// TODO Auto-generated method stub
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext-aop.xml");
TargetObject targetObject=(TargetObject) context.getBean("targetObject");
targetObject.method(22,11);
}
通知方法顺序
哪个在前就会先执行哪一个
jdk的动态代理
前提:对象必须要有实现接口,可以指定这个接口下的哪一个方法
使用jdk的java.lang.reflect.Proxy类的newPRoxyInstance方法实现动态代理
//jdk动态代理
//测试类
@Test
public void test() {
//创建目标对象
com.stone.aop.jdk.proxy.userDao user=new userDaoImpl();
//jdk的动态代理
/*
*newProxyInstance方法的是哪个参数是什么意思
*1、loader:类加载器(类的字节码获得)写法固定
*2、interfaces得到该对象实现接口的字节码对象的数组,写法固定
*3、需要一个实现了InvacationHandler接口的对象,这步需要自己动手实现
* 对目标对象方法功能的增强就是这个对象完成的
*/
InvocationHandler h =new myInvocationHandler(user);
Object newProxyInstance=Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(), h);
userDao proxy=(userDao) newProxyInstance;
proxy.add();
proxy.delete();
}
//实现了InvacationHandler接口的对象
//该类对目标对象进行代理并进行功能增强的具体实现类
public class myInvocationHandler implements InvocationHandler{
//定义目标对象
Object obj;
public myInvocationHandler(Object obj) {
// TODO Auto-generated constructor stub
this.obj=obj;
}
/*
* proxy:被代理的对象(不用)
* method:目标对象的方法对象,jdk传递过来
* args,是该方法对象的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("初始化...");//前置通知...
Object obj2=method.invoke(obj, args);
System.out.println("结束...");//后置通知...
return obj2;
}
}
//对方法判断添加增强
Object obj2=null;
if(method.getName().equals("add")) {
System.out.println("初始化...");//前置通知...
obj2=method.invoke(obj, args);
System.out.println("结束...");//后置通知...
}else {
obj2=method.invoke(obj, args);
}
cglib动态代理java
/*
*不需要接口,也可以指定增强方法
* cglib动态代理的实现步骤
* 1、生成字节码对象(空的)Enhancer
* 2、设定这个字节码对象的父类students(目标对象的类)
* 3、设置增强方法,毁掉方法,拦截的方法
* 4、得到代理对象
*/
@Test
public void test() {
Enhancer en =new Enhancer();//生成字节码对象(空的)Enhancer
en.setSuperclass(Students.class);//设定这个字节码对象的父类students(目标对象的类)
Callback callback = new CallbackMethod();//设置增强方法,毁掉方法,拦截的方法
en.setCallback(callback);//得到代理对象
Students stu=(Students) en.create();
stu.name();
}
public class CallbackMethod implements MethodInterceptor{
/*
* proxy:代理对象
* method:目标对象中方法
* args:目标对象方法的参数
* methodProxy:代理对象中代理对象方法
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("前置方法....");
Object object= methodProxy.invokeSuper(proxy, args);
System.out.println("后置方法....");
return object;
}
}
spring的jdbcTempalte
jdbcTempalte是spring提供的到曾用来和数据库数据交互的技术
jdbcTempalte是spring对jdbc+c3p0的封装
hibernateTemplate 是spring对hibernate又封装一次
mybatis 对jdbc+c3p0的封装
spring的声明式事务
事务特性ACID
原子性:一件完成的事,要不全部成功,要不全部失败
一致性:事务对的前后,数据总数不发生变化
隔离性:只要事务已完成,数据就会到数据库中
持久性:事务具备隔离性,如果没有隔离性,就会发送读取数据的问题
布局别隔离性的话,会发生问题:
脏读
重复读
虚度/幻读:一个事务中,读取了另一个事务还没有提交的数据
spring的事务控制都是基于
配置文件的方式,-------xml方式
<!-- 切面类 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0"></property>
</bean>
<!-- 配置DataSourceTransactionManager里面事务方法的一些参数
不写 该方法使用的事务参数都是默认值
-->
<tx:advice transaction-manager="transactionManager" id="txadvice">
<tx:attributes>
<tx:method name="tranfer"/>
</tx:attributes>
</tx:advice>
<!-- 织入 -->
<aop:config>
<aop:pointcut expression="execution(* cn.itcast.serviceimpl.TranFerServiceImpl.tranfer(..))" id="pointcut"/>
<!-- 针对事务的配置标签 -->
<aop:advisor advice-ref="txadvice" pointcut-ref="pointcut"/>
</aop:config>
事务的注解
<!-- 切面类 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0"></property>
</bean>
<!-- 自己的类 -->
<!-- 开启注解扫描器 -->
<context:component-scan base-package="cn.itcast"></context:component-scan>
<!-- 开启事务的注解配置 告诉使用的是哪个类下的事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
//方法使用注解
@Transactional
// 注解在类上,就是每个方法都配置事务,注解在方法上,就是这个方法开启事务
spring整合hibernate
整合什么?
1)有IOC容器来管理hibernate的seesionFactory
2)让hibernate使用spring的声明式事务
步骤:
先加入hibernate
配置hibernate.cfg.xml
配置hibernate的基本属性
-
数据源需配置到IOC容器中,所以此处不再需要配置数据源
-
关联的hbm.xml也在IOC容器配置sessionfactoey实例再进行配置
-
配置hibernate的基本属性:方言,SQL 显示及格式化,生成数据表的策略以及二级缓存等
再加入spring
整合