第一部分 Spring

工具:idea、maven

第一部分 Spring

一、Spring IOC

1、名词解释

控制反转(Inversion of Control)或又叫依赖注入

控制反转:将对象的创建销毁等动作交由Spring容器管理,传统是直接new,耦合度高。

依赖注入:不同对象之间的依赖关系交由Spring容器管理

2、依赖注入

2.1、使用构造器
<!--class是具体的实现类的限定名-->
<bean id="constructDao" class="com.hjy.spring.inject.xml.construct.dao.ConstructDaoImp"/>
<bean id="constructService" class="com.hjy.spring.inject.xml.construct.service.ConstructServiceImp">
    <constructor-arg index="0" ref="constructDao"/><!--index参数位置-->
</bean>
2.2、使用setter方法(偏多)
<bean id="constructDao" class="com.hjy.spring.inject.xml.setter.dao.ConstructDaoImp"/>
<bean id="constructService" class="com.hjy.spring.inject.xml.setter.service.ConstructServiceImp">
    <!--name注入的对象-->
    <property name="constructDao" ref="constructDao"/>
</bean>

二、Spring Bean

1、bean元素的属性

id、class、scope、、、、、、

2、bean的作用域

scope="singleton" 每次获取bean都返回同一个bean对象,spring容器管理
scope="prototype" 每次获取bean都创建并返回新的bean对象,spring容器不管理

3、bean的装配方式

3.1、xml装配

​ 在xml文件中写好各个类的属性,适用于后期开发改动大

3.2、注解装配

​ 在xml文件只需设置扫描包路径,spring容器会自动将这些类与关系纳入到管理中,前提是代码中需要设置注解

注解类型

​ 1.@Component,单单表示组件对象,一般用于pojo

​ 2.@Repository,注解dao层

​ 3.@Service,注解service层

​ 4.@Controller,注解controller层

​ 5.@Autowired,注解成员变量,方法和构造方法,通过类型来装配

​ 6.@Resource,和@Autowired功能一样,但是实现不一样,通过名称来装配(java自带的)

​ 7.@Qualifier,和@Autowired一起使用,存在多个实例时使用

三、Spring AOP

1、名词解释

AOP:即面向切面编程,与传统的OOP(面向对象编程)不同,AOP的优点是能将与业务逻辑代码无关的重复部分抽取到一个类中,使用时只需将这些抽取出的代码应用到业务逻辑代码即可,这样大大降低了代码的耦合度,在后期维护代码也很方便,注意,AOP和OOP相辅相成,没有替代性可言。

1.1、AOP的术语

1、 目标类target:就是我们需要增强的那个类 LaoZong.class
2、 代理类proxy:就是自定义的代理的对象 $Proxy0.class
3、 连接点joinPoint:程序执行的某个特定位置,Spring仅支持方法的连接点
eat(),sleep(),run()
4、 切入点pointCut:就是在目标类中实际增强的方法
eat()
5、 织入weave:就是将代理类中需要增强的方法放入到目标类中去执行的过程
将原方法与其他类的方法一起调用
6、 引介Introduction:引介是一种特殊的增强,它为类添加一些属性和方法(课程不使用)
7、 通知advice:将代理对象中的方法应用到目标类的过程中产生的结果。
8、 切面aspect:所有的切入点和代理对象的方法组成在一起构成了切面

2、JDK动态代理

前提:目标类有实现接口

1、创建目标类(业务逻辑类)
2、创建切面类(里面包含增强方法)
3、创建代理类(必须实现InvocationHandler接口)
public class MyProxy implements InvocationHandler {
    //目标接口对象成员
    private TestDao dao;
    //建立代理对象与目标对象的关系,返回代理对象
    public Object creatProxy(TestDao dao) {
        //初始化目标对象
        this.dao = dao;
        //1.获取代理类的类加载器
        ClassLoader classLoader = MyProxy.class.getClassLoader();
        //2.获取目标类所实现的所有接口
        Class[] clazz = dao.getClass().getInterfaces();
        //3.返回增强后的目标对象(代理对象)
        return Proxy.newProxyInstance(classLoader, clazz, this);
    }
    
    //回调方法,代理类使用目标类的方法时调用,proxy代理对象,method被执行的方法,args参数
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行业务逻辑前可以做的事");
        //创建切面对象
        MyAspect aspect = new MyAspect();
        //前置通知
        
        //传入目标对象和参数,调用业务方法
        Object obj = method.invoke(dao, args);
        //后置通知
        
        return obj;
    }
}
4.测试类
public static void main(String[] args) {
    //1.创建目标对象
    TestDao dao = new TestDaoImp();
    //2.创建代理对象
    MyProxy proxy = new MyProxy();
    //3.创建被代理好的目标对象
    TestDao dao = (TestDao)proxy.creatProxy(TestDao);
    //4.执行被代理类增强了的目标类的方法
    dao.query();
    dao.insert();
}

3.CGlib动态代理

原理:采用字节码技术,对目标类生成子类,对子类增强代理.

1.创建目标类

2.创建切面类

3.创建代理类(实现MehtodInterceptor)

public class CGlibProxy implements MethodInterceptor {//cglib包的MethodInterceptor

    //创建代理对象,建立代理对象和目标对象的关系
    public Object creatProxy(Object target) {
        //1.创建代理类对象
        Enhancer enhancer = new Enhancer();
        //2.设置目标类为代理类的父类
        enhancer.setSuperclass(target.getClass());
        //3.设置代理类对象调用本类的intercept方法(回调)
        enhancer.setCallback(this);
        //4.返回创建好的代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //1.创建切面类
        MyAspect aspect = new MyAspect();
        //2.前置增强
        aspect.check();
        aspect.exception();
        //3.代理类执行目标对象方法
        Object obj = methodProxy.invokeSuper(proxy, objects);
        //4.后置增强
        aspect.log();
        return obj;
    }
}

4.测试类

public class App {
    public static void main(String[] args) {
        //1.创建代理对象
        CGlibProxy proxy = new CGlibProxy();
        //2.创建目标对象
        CGlibProxyDao dao = new CGlibProxyDao();
        //3.创建增强了的目标对象(被代理了的目标对象)
        CGlibProxyDao daoAdvice = (CGlibProxyDao)proxy.creatProxy(dao);
        //4.执行增强了的方法
        daoAdvice.query();
        daoAdvice.insert();
        daoAdvice.delete();
    }
}

4.基于代理类的AOP实现

通知分类

前置通知:目标方法执行前增强

后置返回通知:目标方法执行成功后增强

环绕通知:目标方法执行前后增强

后置(最终)通知:目标方法执行后增强,相当于finally

异常通知:目标方法执行抛出异常后增强

引入通知:在目标类中增加方法和属性

1、创建目标类(需要接口)
2、创建切面类,并实现Method Interceptor接口(aopalliance包中的)
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
    //前置通知
    check();
    //目标类方法执行
    Object proceed = methodInvocation.proceed();
    //后置通知
    log();
    return proceed;
}
3、配置xml文件(重要)
<!--配置目标类bean-->

<!--配置切面类bean-->

<!--配置代理类bean-->
<bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!--指定目标对象-->
	<property name="target" ref="myDao"/>
    <!--指定代理类实现的接口-->
	<property name="proxyInterfaces" value="myDao接口的限定名"/>
    <!--指定切面类,织入通知-->
	<property name="interceptorNames" value="myAspect"/>
    <!--指定代理方式,默认false jdk代理-->
	<property name="proxyTargetClass" value="true"/>
</bean>
4、测试类
public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("com/hjy/spring/aop/proxyfactory/xml/applicationContext.xml");
        MyDao myDao = (MyDao) applicationContext.getBean("proxyFactory");
        myDao.search();
        myDao.delete();
    }
}

5、AspectJ开发(用的多)

XML
1、创建目标类
2、创建切面类
public class MyAspect {
    /*
    前置通知
    JointPoint接口获得目标对象信息*/
    public void before(JoinPoint joinPoint) {
        System.out.println("前置通知,权限检查");
        System.out.println("目标类对象:" + joinPoint.getTarget() + "被增强的方法:" + joinPoint.getSignature().getName());
    }

    /*
    后置返回通知
    JointPoint接口获得目标对象信息*/
    public void afterReturning(JoinPoint joinPoint) {
        System.out.println("后置返回通知,删除临时文件 ");
        System.out.println("目标类对象:" + joinPoint.getTarget() + "被增强的方法:" + joinPoint.getSignature().getName());
    }

    /*
    环绕通知
    ProceedingJoinPoint是JoinPoint接口的子接口,代表可以执行的目标方法
    返回值必须为Object
    必须抛出Throwable异常
    参数必须是ProceedingJoinPoint类型*/
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知开始,开启事务");
        System.out.println("目标类对象:" + joinPoint.getTarget() + "被增强的方法:" + joinPoint.getSignature().getName());
        //执行目标类的方法
        Object proceed = joinPoint.proceed();
        System.out.println("环绕通知结束,关闭事务");
        return proceed;
    }

    /*异常通知*/
    public void except(Throwable e) {
        System.out.println("异常通知:" + e.getMessage());
    }

    /*后置(最终)通知*/
    public void after() {
        System.out.println("最终通知,释放资源");
    }
}
3、配置xml文件
<!--定义目标类和切面类-->
<bean id="myDao" class="com.hjy.spring.aop.aspectj.xml.dao.MyDaoImp"/>
<bean id="myAspect" class="com.hjy.spring.aop.aspectj.xml.aspect.MyAspect"/>

<!--配置AOP-->
<aop:config>
    <!--配置切面-->
    <aop:aspect ref="myAspect">
        <!--配置切入点,就是切面要增强的哪些方法-->
        <!--第一个*代表返回类型不限制,第二个*代表这个包下所有类,注意dao下不能再有包文件,第三个*代表任意方法,(..)代表任意参数-->
        <aop:pointcut id="myPointCut" expression="execution(* com.hjy.spring.aop.aspectj.xml.dao.*.*(..))"/>
        <!--关联通知-->
        <aop:after-returning method="afterReturning" pointcut-ref="myPointCut"/>
        <aop:after method="after" pointcut-ref="myPointCut"/>
        <aop:around method="around" pointcut-ref="myPointCut"/>
        <aop:before method="before" pointcut-ref="myPointCut"/>
        <aop:after-throwing method="except" pointcut-ref="myPointCut" throwing="e"/>
    </aop:aspect>
</aop:config>

注意:通知的执行顺序和xml文件的配置顺序有关

4、测试
public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("com/hjy/spring/aop/aspectj/xml/applicationContext.xml");
        MyDao myDao = (MyDao)context.getBean("myDao");
        myDao.search();
        //myDao.delete();
    }
}
注解(用的多)
1、创建目标类
2、创建切面类
@Aspect
@Component
public class MyAspect {

    //需要定义一个空方法作为切点
    @Pointcut("execution(* com.hjy.spring.aop.aspectj.annotation.dao.*.*(..))")
    private void myPointCut() {

    }

    /*
    前置通知
    JointPoint接口获得目标对象信息*/
    @Before("myPointCut()")
    public void before(JoinPoint joinPoint) {
        System.out.println("前置通知,权限检查");
        System.out.println("目标类对象:" + joinPoint.getTarget() + "被增强的方法:" + joinPoint.getSignature().getName());
    }

    /*
    后置返回通知
    JointPoint接口获得目标对象信息*/
    @AfterReturning("myPointCut()")
    public void afterReturning(JoinPoint joinPoint) {
        System.out.println("后置返回通知,删除临时文件 ");
        System.out.println("目标类对象:" + joinPoint.getTarget() + "被增强的方法:" + joinPoint.getSignature().getName());
    }

    /*
    环绕通知
    ProceedingJoinPoint是JoinPoint接口的子接口,代表可以执行的目标方法
    返回值必须为Object
    必须抛出Throwable异常
    参数必须是ProceedingJoinPoint类型*/
    @Around("myPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知开始,开启事务");
        System.out.println("目标类对象:" + joinPoint.getTarget() + "被增强的方法:" + joinPoint.getSignature().getName());
        //执行目标类的方法
        Object proceed = joinPoint.proceed();
        System.out.println("环绕通知结束,关闭事务");
        return proceed;
    }

    /*异常通知*/
    @AfterThrowing(value = "myPointCut()", throwing = "e")
    public void except(Throwable e) {
        System.out.println("异常通知:" + e.getMessage());
    }

    /*后置(最终)通知*/
    @After("myPointCut()")
    public void after() {
        System.out.println("最终通知,释放资源");
    }
}
3、配置xml文件
<!--扫描包,管理bean-->
<context:component-scan base-package="com.hjy.spring.aop.aspectj.annotation"/>
<!--启动支持-->
<aop:aspectj-autoproxy/>
4、测试
public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("com/hjy/spring/aop/aspectj/annotation/applicationContext.xml");
        MyDao myDao = (MyDao)context.getBean("myDao");
        myDao.search();
        //myDao.delete();
    }
}

第四章:Spring的事务管理

1、Spring JdbcTemplate(了解)

2、编程式事务管理(了解)

3、声明式事务管理***

是通过AOP技术实现的事务管理,是对方法的拦截,对方法执行前创建一个事务,根据方法执行情况提交或者回滚事务
image-20201017101940358

3.1 基于xml
1、创建dao层
@Repository("myDao")
public class MyDaoImp implements com.hjy.spring.transaction.xml.dao.MyDao {

    @Autowired//注入jdbctemplate
    private JdbcTemplate jdbcTemplate;

    @Override
    public int save(String sql, Object[] param) {
        //增删改都是update方法,查询是query
        return jdbcTemplate.update(sql, param);
    }

    @Override
    public int delete(String sql, Object[] param) {
        return jdbcTemplate.update(sql, param);
    }
}
2、创建service层
@Service("myService")
public class MyServiceImp implements MyService {

    @Autowired//注入dao层
    private MyDao myDao;

    @Override
    public void call() {
        //创建好要执行的sql语句
        String saveSql = "insert into user values(?, ?, ?)";
        String deleteSql = "delete from user";
        //参数
        Object[] param = {1, "HJY", "Man"};
        //调用dao层的方法运行sql语句
        myDao.delete(deleteSql, null);
        myDao.save(saveSql, param);
        //myDao.save(saveSql, param);
    }
}
3、创建controller层
@Controller
public class MyController {

    @Autowired//注入service层
    private MyService myService;

    public void call() {
        myService.call();
    }
}
4、配置xml文件(重点)
<!--扫描包-->
<context:component-scan base-package="com.hjy.spring.transaction"/>

<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <!--MySql数据库驱动-->
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <!--Url-->
    <property name="url" value="jdbc:mysql://localhost/test?useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=false&amp;serverTimezone=UTC"/>
    <!--username-->
    <property name="username" value="root"/>
    <!--password-->
    <property name="password" value="123456"/>
</bean>

<!--Jdbc模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--1.要在bean.xml中创建spring的平台事务管理器  (DataSourceTransactionManager   )  注入dataSource-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--2.我们需要创建一个 tx:advice 增强-->
<!--里面定义了筛选那些方法进行事务控制, 设置事务的隔离级别规则,  设置事务传播行为的规则  , 设置事务超时时间  设置事务是否只读..-->
<tx:advice id="myAdvice" transaction-manager="txManager">
    <tx:attributes>
        	<!--
                该增强中的规则:
                name代表筛选那些方法收到事务的增强
                isolation : 隔离级别 REPEATABLE_READ 可重复读
                propagation: 传播行为
                read-only: 是否为只读事务
                timeout: 事务是否超时
            -->
        <tx:method name="translate" isolation="REPEATABLE_READ"  propagation="REQUIRED" read-only="false" timeout="-1" />
        <!--任意方法都使用这个事务-->
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<!--AOP,生成代理-->
<aop:config>
    <!--切入点:实际要增强的方法-->
    <aop:pointcut id="txPointCut" expression="execution(* com.hjy.spring.transaction.xml.service.*.*(..))"/>
    <!--切面,将切入点与通知关联-->
    <aop:advisor advice-ref="myAdvice" pointcut-ref="txPointCut"/>
</aop:config>
3.2 基于annotation

前几个步骤和基于xml的事务管理是一样的,一般事务管理通常在service层,@Transactional注解可以添加在接口类、接口方法、普通类和普通方法上,注解放在接口上时只有使用基于接口代理时才会生效,注解放在类上代表类中所有的public方法都会有事务的属性

xml文件(把配置事务属性和aop部分去掉)

<!--为事务管理器注册注解驱动器-->
<tx:annotation-driven transaction-manager="txManager"/>
4、事务处理中捕获异常

如果在数据存储过程中发生异常,正常情况下必须进行事务回滚,也就是异常之前的数据库操作全部取消,但是如果将异常捕获,事务就不会发生回滚,这破坏了事务的特性,在捕获异常后加上下面的一句就行了

public void call() {
    String saveSql = "insert into user values(?, ?, ?)";
    String deleteSql = "delete from user";
    Object[] param = {1, "HJY", "Man"};
    try {
        myDao.delete(deleteSql, null);
        myDao.save(saveSql, param);
        myDao.save(saveSql, param);
    } catch (Exception e) {
        System.out.println("主键重复,事务回滚");
        //加上之后即使异常被捕获事务也会发生回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

总结

Spring这一章主要讲了IOCAOP事务控制这三个方面

其中IOC即控制反转,IOC将对象的创建延迟了,在代码中没有直接对对象的创建,而是交由给spring容器进行管理,减少了代码的冗余程度,IOC的实现有通过xml配置和注解Annotation配置这两种方式,bean的创建一般使用setter的方式。注解的类型分为@Componet(普通组件)、@Repository、@Service、@Controller、@Autowired等。

AOP即面向切面编程,是对OOP的补充,AOP将与业务代码无关的部分抽取出来放到一个切面类里,使用的时候创建业务类的代理类使得业务类的方法得以增强,代码的耦合度降低,这种方式让开发人员更专注与功能的实现,效率提高。AOP分为JDK动态代理(默认),CGlib动态代理和AspectJ框架代理,JDK代理前提是业务类实现了接口,需要自己创建代理类并实现InvocationHandler接口,CGlib代理采用的是底层字节码技术,用于对业务类生成一个子类,对其子类进行增强,创建的代理类需实现MethodInterceptor接口。AOP的使用过程中,AspectJ是使用的最多的,它是基于Java语言的框架,具体实现方式分为xml和annotation。

事务控制一般使用声明式的事务管理,controller调用service层调用dao层,在dao层需要注入spring的JdbcTemplate,声明式的事务管理也分为xml和annotation。事务的特性分为1、一致性(数据修改前后一致) 2、原子性(要么都做要么都不做) 3、隔离性(操作不相互影响) 4、持久性(写到硬盘)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值