Hz零基础学习Spring

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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值