Spring

Spring 特点

 1. 提供了IoC容器,方便解耦,简化开发;
 2. 支持AOP,面向切面编程;
 3. 支持声明式事务;
 4. 方便程序的测试;
 5. 方便集成其它框架;

Spring 组织架构

在这里插入图片描述

Spring 核心模块

 1. spring-core:提供了框架的基本组成部分,包括IoC和DI功能;
 2. spring-beans:提供BeanFactory;
 3. spring-context:spring的上下文,即IoC容器;
 4. spring-context-support:提供对第三方集成到spring上下文的支持;
 5. spring-expression:spring表达式语言;

1、Spring IoC

IoC,inverse of control 控制反转。即把原来需要通过 new 关键字创建的对象交由 IoC 容器来管理。

1.1、两种容器

 BeanFactory 和 ApplicationContext;
 ApplicationContext是BeanFactory的子接口,实现了BeanFactory的所有功能,还扩展了其它功能,是一种高级的容器,一般建议使用ApplicationContext。

1.2、ApplicationContext 接口实现

 1. ClassPathXmlApplicationContext***:该容器从XML文件中加载已被定义的bean。不需要提供XML文件的完整路径,会从CLASSPATH中搜索bean配置文件;
 2. FileSystemXmlApplicationContext:需要提供XML文件的完整路径;

1.3、基于XML配置文件的实现过程

1.3.1、添加依赖

<dependencies>
	<!--spring的核心工具包-->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-core</artifactId>
	    <version>5.2.9.RELEASE</version>
	</dependency>
	<!--spring IoC的基础实现,包含访问配置文件、创建和管理bean等-->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-beans</artifactId>
	    <version>5.2.9.RELEASE</version>
	</dependency>
	<!--在基础IoC功能上提供扩展服务,邮件服务、任务调度、远程访问等-->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-context</artifactId>
	    <version>5.2.9.RELEASE</version>
	</dependency>
	<!--spring context的扩展支持-->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-context-support</artifactId>
	    <version>5.2.3.RELEASE</version>
	</dependency>
	<!--spring表达式语言-->
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-expression</artifactId>
	    <version>5.2.9.RELEASE</version>
	</dependency>
	<!--测试工具-->
	<dependency>
	    <groupId>junit</groupId>
	    <artifactId>junit</artifactId>
	    <version>4.12</version>
	</dependency>
</dependencies>

1.3.2、创建配置文件applicationContext.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 id="对象名" class="类的完整路径">
        <property name="属性名" ref="被引用的对象id"></property>
    </bean>
    
</beans>

1.3.3、加载配置文件,获取对象

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Object obj = context.getBean("对象id");

1.4、bean标签的属性

在这里插入图片描述

1.5、对象创建的方式

1.5.1 无参构造

	public StudentDao() {
        System.out.println("使用了无参构造");
    }
    
    <bean id="studentDao" class="com.zhy.dao.StudentDao"></bean>

1.5.2 有参构造

	public StudentDao(String name, int age) {
        System.out.println("使用了有参构造:"+name+","+age);
        this.name = name;
        this.age = age;
    }

	<!--有参构造-->
    <bean id="studentDao1" class="com.zhy.dao.StudentDao">
        <constructor-arg name="name" value="周二宇"></constructor-arg>
        <constructor-arg name="age" value="20"></constructor-arg>
    </bean>

1.5.3 静态方法

	public static void static_method(){
        System.out.println("调用了静态方法");
    }

	<bean id="studentDao2" class="com.zhy.dao.StudentDao" factory-method="static_method"></bean>

1.5.4 非静态方法

	public void no_static_method(){
        System.out.println("调用了非静态方法");
    }

	<bean id="studentDao" class="com.zhy.dao.StudentDao"></bean>
	<bean id="studentDao4" factory-method="no_static_method" factory-bean="studentDao"></bean>

1.6、基于注解的实现过程

1.6.1、配置注解扫描

<!--会扫描指定包及所有子包-->
<context:component-scan base-package="指定扫描的包"></context:component-scan>

1.6.2、注解

 1. 添加在类上
	@Component:表示将类标记为容器中的一个bean; 
	@Service // service层
	@Controller// controller层
	@Repository // dao层
	@Scope(scopeName="singleton") //单例对象
	@Scope(scopeName="prototype") //多例对象
 2. 添加在属性上
	@Value("属性值")
	@Autowired
	@Qualifier("bean name"):一个接口类型同时有两个实现类,@Autowired会报错,使用@Qualifer指定bean;
 3. 添加在方法上
	@PostConstruct:等价于init-method属性;
	@PreDestroy:等价于destroy-method属性;

2、DI

DI,Dependency Injection,即依赖注入。当容器创建bean实例时,将bean实例属性的值注入。

2.1 Set注入

 1. 基本属性类型值
	<property name="" value=""/>
 2. 引用属性类型值
	<property name="" ref="bean id">

注意:类中需要定义set方法。

2.2 构造注入

 1. 通过name属性,按照参数名赋值
	<bean id="StudentDao1" class="com.zhy.dao.StudentDao">
        <constructor-arg name="name" value="周大宇"></constructor-arg>
        <constructor-arg name="age" value="20"></constructor-arg>
    </bean>
 2. 通过index属性,按照参数索引赋值,从0开始
	<bean id="StudentDao2" class="com.zhy.dao.StudentDao">
        <constructor-arg index="0" value="周大宇"></constructor-arg>
        <constructor-arg index="1" value="22"></constructor-arg>
    </bean>
 3. 通过type属性,按照参数类型赋值
	<bean id="StudentDao3" class="com.zhy.dao.StudentDao">
        <constructor-arg type="java.lang.String" value="周三宇"></constructor-arg>
        <constructor-arg type="int" value="24"></constructor-arg>
    </bean>

对应实体类:
	public class StudentDao{
	    private String name;
	    private int age;
    }

2.3 spring el 表达式

<bean id="classDao" class="com.zhy.dao.ClassDao">
    <property name="classId" value="1001"></property>
</bean>

<bean id="studentDao" class="com.zhy.dao.StudentDao" p:classDao-ref="classDao">
    <property name="name" value="周大宇"></property>
    <property name="age" value="20"></property>
    <property name="classDao" value="#{classDao.classId}"></property>
</bean>

2.4 p命名空间

<bean id="studentDao" class="com.zhy.dao.StudentDao" p:name="周大宇" p:age="20"></bean>

2.5 复杂类型

实体类:
public class Demo {
    private Object[] arr;
    private ArrayList list;
    private Set set;
    private Map map;
    private Properties properties;

   setter、getter省略
}

<bean id="studentDao" class="com.zhy.dao.StudentDao"></bean>
<bean id="demo" class="com.zhy.dao.Demo">
    <!--数组-->
    <property name="arr">
        <list>
            <value>数组值1</value>
            <value>数组值2</value>
            <value>数组值3</value>
            <ref bean="studentDao"/>
        </list>
    </property>
    <!--list集合-->
    <property name="list">
        <list>
            <value>list集合值1</value>
            <value>list集合值2</value>
            <value>list集合值3</value>
            <list>
                <value>集合中的集合值1</value>
                <value>集合中的集合值2</value>
                <value>集合中的集合值3</value>
            </list>
            <ref bean="studentDao"></ref>
        </list>
    </property>
    <!--Set-->
    <property name="set">
        <set>
            <value>Set集合值1</value>
            <value>Set集合值2</value>
            <value>Set集合值3</value>
            <ref bean="studentDao"></ref>
        </set>
    </property>
    <!--map-->
    <property name="map">
        <map>
            <entry key="k1" value="v1"></entry>
            <entry key="k2" value="v2"></entry>
            <entry key="k3" value="v3"></entry>
            <entry key="ref" value-ref="studentDao"></entry>
        </map>
    </property>
    <!--properties-->
    <property name="properties">
        <props>
            <prop key="name">周大宇</prop>
            <prop key="password">123456</prop>
        </props>
    </property>
</bean>

2.6 自动注入

<bean id="" class="" autowire=""></bean>

autowire属性:
	no:不自动装配;
	byName:通过name自动装配(属性的名称=bean的id),调取set方法赋值;
	byType:通过类型自动装配(属性的类型=bean的类型),当有多个相同类型的对象时会报错,调取set方法赋值;
	constructor:通过构造方法自动装配(构造方法参数的类型=bean的类型);

3、AOP

AOP,Aspect Oriented Programming,即面向切面编程。在不改变原程序的基础上为代码段增加新的功能。应用在权限认证、日志、事务。

3.1 JDK动态代理

JDK动态代理,针对实现了接口的类产生代理,代理类实现InvacationHandler接口。
接口:
	public interface JdkService {
	    void login();
	}
实现类:
	public class JdkServiceImpl implements JdkService {
	    @Override
	    public void login() {
	        System.out.println("真实方法执行");
	    }
	}
代理类:
	public class JdkProxy implements InvocationHandler {
	    //目标对象
	    private JdkService target;
	
	    public JdkProxy(JdkService target){
	        this.target = target;
	    }
	
	    @Override
	    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	        System.out.println("前置增强");
	        //被代理的类
	        Object invoke = method.invoke(target, args);
	        System.out.println("后置增强");
	        return invoke;
	    }
	}
测试:
	@Test
    public void jdkProxyTest(){
        //真实角色
        JdkService jdkService = new JdkServiceImpl();
        //代理角色
        JdkProxy jdkProxy = new JdkProxy(jdkService);
        JdkService service = (JdkService) Proxy.newProxyInstance(jdkService.getClass().getClassLoader(), jdkService.getClass().getInterfaces(), jdkProxy);
        service.login();
    }

3.2 CGLIB动态代理

CGlib动态代理,针对没有实现接口的类产生代理,应用的是底层的字节码增强技术,生成当前类的子类对象,实现MethodInterceptor接口。
添加依赖:
	<dependency>
	    <groupId>cglib</groupId>
	    <artifactId>cglib</artifactId>
	    <version>2.2.2</version>
	</dependency>
普通类:
	public class User {
	    public void login(){
	        System.out.println("真实方法执行");
	    }
	}
代理类:
	public class CglibProxy implements MethodInterceptor {
	    @Override
	    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
	        System.out.println("前置增强");
	        Object obj = methodProxy.invokeSuper(o, objects);
	        System.out.println("后置增强");
	        return obj;
	    }
	}
测试:
	@Test
    public void cglibProxyTest(){
        //真实角色
        User user = new User();
        //代理角色
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(user.getClass());
        enhancer.setCallback(new CglibProxy());
        User u = (User) enhancer.create();
        u.login();
    }

3.3 Spring中使用AOP

aop:before(前置通知):目标方法运行之前调用;
aop:after-returning(后置通知):目标方法运行之后调用,出现异常则不会调用;
aop:around(环绕通知):在目标方法前后调用;
aop:after(最终通知):目标方法运行之后调用;
aop:after-throwing(异常通知):程序出现异常时执行;
添加依赖:
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-core</artifactId>
	    <version>5.2.9.RELEASE</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-beans</artifactId>
	    <version>5.2.9.RELEASE</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-context</artifactId>
	    <version>5.2.9.RELEASE</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-context-support</artifactId>
	    <version>5.2.3.RELEASE</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-aop</artifactId>
	    <version>5.2.9.RELEASE</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-aspects</artifactId>
	    <version>5.2.6.RELEASE</version>
	</dependency>
	<dependency>
	    <groupId>org.aspectj</groupId>
	    <artifactId>aspectjweaver</artifactId>
	    <version>1.9.5</version>
	</dependency>
	<dependency>
	    <groupId>aopalliance</groupId>
	    <artifactId>aopalliance</artifactId>
	    <version>1.0</version>
	</dependency>
接口:
	public interface UserDao {
	    void test1();
	}

	public interface UserService {
	    void test1();
	    void test2();
	}
实现类:
	public class UserDaoImpl implements UserDao {
	    @Override
	    public void test1() {
	        System.out.println("UserDaoImpl---test1");
	    }
	}

	public class UserServiceImpl implements UserService {
	
	    private UserDao userDao;
	
	    public void setUserDao(UserDao userDao) {
	        this.userDao = userDao;
	    }
	
	    @Override
	    public void test1() {
	        userDao.test1();
	    }
	
	    @Override
	    public void test2() {
	        System.out.println("UserServiceImpl---test2");
	        int i= 10/0;
	    }
	}
切面:
	public class MyAspect {
	
	    public void before(){
	        System.out.println("前置增强");
	    }
	
	    public void after_returning(){
	        System.out.println("后置增强");
	    }
	
	    public void around(ProceedingJoinPoint point) throws Throwable {
	        System.out.println("环绕增强前");
	        point.proceed();
	        System.out.println("环绕增强后");
	    }
	
	    public void after(){
	        System.out.println("最终增强");
	    }
	
	    public void after_throwing(){
	        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" xmlns:aop="http://www.springframework.org/schema/aop"
	       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
	
	    <bean id="userDao" class="com.springaop.dao.impl.UserDaoImpl"></bean>
	
	    <bean id="userService" class="com.springaop.service.impl.UserServiceImpl">
	        <property name="userDao" ref="userDao"></property>
	    </bean>
	
	    <bean id="myAspect" class="com.springaop.aspect.MyAspect"></bean>
	
	    <aop:config>
	        <aop:pointcut id="mypoint" expression="execution(* com.springaop.service.impl.*.*(..))"/>
	        <aop:aspect ref="myAspect">
	            <aop:before method="before" pointcut-ref="mypoint"/>
	            <aop:after-returning method="after_returning" pointcut-ref="mypoint"/>
	            <aop:around method="around" pointcut-ref="mypoint"/>
	            <aop:after method="after" pointcut-ref="mypoint"/>
	            <aop:after-throwing method="after_throwing" pointcut-ref="mypoint"/>
	        </aop:aspect>
	    </aop:config>
	
	</beans>
测试类:
	@Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService");
        userService.test1();
        userService.test2();
    }

4、Spring事务管理

Spring的事务和数据库事务基本一致。

4.1 事务的传播行为

在这里插入图片描述
Spring事务传播行为详解

4.1.1 @Transactional属性

在这里插入图片描述

4.1.2 Demo

bean:
	public class Account implements Serializable{
    private Integer id;
    private String name;
    private Float money;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getMoney() {
        return money;
    }

    public void setMoney(Float money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}';
    }
}
dao层:
	public interface AccountDao {
    /**
     * 根据id查找账户信息
     * @param id
     * @return
     */
    Account findAccountById(Integer id);

    /**
     * 根据名称查找账户信息
     * @param name
     * @return
     */
    Account findAccountByName(String name);

    /**
     * 跟新账户信息
     * @param account
     */
    void updateAccount(Account account);
dao实现类:
	public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
    /**
     * 根据id查找账户信息
     *
     * @param id
     * @return
     */
    @Override
    public Account findAccountById(Integer id) {
        String sql = "select * from account where id = ?";
        List<Account> list = getJdbcTemplate().query(sql, new AccountRowMapper(), id);
        return list.isEmpty()?null:list.get(0);
    }

    /**
     * 根据名称查找账户信息
     *
     * @param name
     * @return
     */
    @Override
    public Account findAccountByName(String name) {
        String sql = "select * from account where name = ?";
        List<Account> list = getJdbcTemplate().query(sql, new AccountRowMapper(), name);
        if (list.isEmpty()){
            return null;
        }
        if(list.size()>1){
            throw new RuntimeException("账户不唯一");
        }
        return list.get(0);
    }

    /**
     * 跟新账户信息
     *
     * @param account
     */
    @Override
    public void updateAccount(Account account) {
        String sql = "update account set money=? where id= ?";
        getJdbcTemplate().update(sql,account.getMoney(),account.getId());
    }
}

service层:
	public interface AccountService {

    /**
     * 根据id查找账户信息
     * @param id
     * @return
     */
    Account findAccountById(Integer id);

    /**
     * 转账
     * @param sourceName
     * @param targeName
     * @param money
     */
    void transfer(String sourceName,String targeName,Float money);

}

service层实现类:
	public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    /**
     * 根据id查找账户信息
     *
     * @param id
     * @return
     */
    @Override
    public Account findAccountById(Integer id) {
        return accountDao.findAccountById(id);
    }

    /**
     * 转账
     *
     * @param sourceName
     * @param targeName
     * @param money
     */
    @Override
    public void transfer(String sourceName, String targeName, Float money) {
        //根据名称查找两个账户
        Account source = accountDao.findAccountByName(sourceName);
        Account targe = accountDao.findAccountByName(targeName);
        //修改两个账户的金额
        source.setMoney(source.getMoney()-money);
        targe.setMoney(targe.getMoney()+money);
        //跟新转账之后的两个账户
        accountDao.updateAccount(source);
        //出现异常
        int i = 10/0;
        accountDao.updateAccount(targe);
    }
}

RowMapper实现类:
	public class AccountRowMapper implements RowMapper<Account> {

    @Override
    public Account mapRow(ResultSet resultSet, int i) throws SQLException {
        Account account = new Account();
        account.setId(resultSet.getInt("id"));
        account.setName(resultSet.getString("name"));
        account.setMoney(resultSet.getFloat("money"));
        return account;
    }
}

配置文件:
	<?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" xmlns:tx="http://www.springframework.org/schema/tx"
	       xmlns:aop="http://www.springframework.org/schema/aop"
	       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
	
	    <!--加载db.properties-->
	    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
	    <!--配置数据源-->
	    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	        <property name="driverClassName" value="${driver}"/>
	        <property name="url" value="${url}"/>
	        <property name="username" value="${username}"/>
	        <property name="password" value="${password}"/>
	    </bean>
	    <!--配置jdbcTemplate-->
	    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
	        <property name="dataSource" ref="dataSource"/>
	    </bean>
	
	    <bean id="accountDao" class="dao.impl.AccountDaoImpl">
	        <property name="dataSource" ref="dataSource"></property>
	    </bean>
	    <bean id="accountService" class="service.impl.AccountServiceImpl">
	        <property name="accountDao" ref="accountDao"></property>
	    </bean>
	
	    <!--配置事务管理器-->
	    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	        <property name="dataSource" ref="dataSource"></property>
	    </bean>
	    <!--配置事务-->
	    <tx:advice id="txAdvice" transaction-manager="transactionManager">
	        <tx:attributes>
	            <tx:method name="*" propagation="REQUIRED"/>
	            <tx:method name="find*" propagation="SUPPORTS"/>
	        </tx:attributes>
	    </tx:advice>
	    <!--配置aop-->
	    <aop:config>
	        <aop:pointcut id="pointcut" expression="execution(* service.impl.*.*(..))"/>
	        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
	    </aop:config>
	
	</beans>

测试类:
	public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService service = (AccountService) context.getBean("accountService");
        service.transfer("周大宇","周二宇",10000f);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值