03-Spring相关

spring总结

一、spring中的ioc

所谓的IOC一句话搞定:对象由Spring 来创建,管理,装配。ioc叫做控制反转,是spring的核心

ioc是一种思想 ,有一些实现方式,其中较为常用的一种是依赖注入(Dependency Injection,简称DI),依赖注入是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。

实现方式,依赖注入,注入bean让spring去管理。默认bean的作用域是单例的singleton

依赖注入让 Spring 的Bean之间以配置文件的方式组织在一起,而不是以硬编码的方式耦合在一起。

spring中还提供了跟@Component等效的注解,通常情况下,我们会使用下面注解来代替@Component:

@Repository 用于对 DAO 实现类进行注解
@Service 用于对 Service 实现类进行注解
@Controller 用于对 Controller 实现类进行注解

@Autowired是按类型自动转配的,不支持id匹配。
需要导入 spring-aop的包!

1.1首先要在pom.xml中导入相关的依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.4.RELEASE</version>
</dependency>

1.2在resources目录下新建applicationContext.xml,并添加相关的约束,

注册bean后,这些类就由spring去管理了

<?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 id="mysql" class="com.kuang.dao.UserDaoImplMysql"/>
        <bean id="oracle" class="com.kuang.dao.UserDaoImplOracle"/>
        <bean id="userService" class="com.kuang.service.UserServiceImpl">
            <property name="userDao" ref="oracle"/>
        </bean>
    
<!--方式二:注解版-->    
    <!--注解扫描-->
    <context:component-scan base-package="com.kuang"/>
    <!--自动配置注解,@Autowired-->
    <context:annotation-config/>

</beans>

UserServiceImpl类

package com.kuang.service;

import com.kuang.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    /*public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }*/

    public void getUser() {
        userDao.getUser();
    }
}

Userdao类

package com.kuang.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImplMysql implements UserDao {

    public void getUser() {
        System.out.println("MySQL获取用户数据!");
    }
}

Test类

public static void main(String[] args) {

    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService userService = (UserService) context.getBean("userService");
    userService.getUser();
    //结果:最后打印出了MySQL获取用户数据!
}

总结:

方式一配置版:需要手动添加bean,并且UserServiceImpl类中要有一个属性UserDao接口,还有有set方法。

方式二注解版:要添加一个注解扫描,自动配置的支持,这样UserServiceImpl就不需要有set方法了,直接在属性

上添加一个注解@Autowired,和在实现类上添加@Service(“userService”)注解,在Userdao类中要添加注解@Repository,

注意:使用注解开发时在测试类中获取bean的时候,如果@Service() 注解如果没有指定bean的名字,默认为小写开头的类名。例如类名是UserServiceImpl,则spring返回userServiceImpl的bean名。 不然控制台会报错没有找到bean

二、使用java配置类@Configuration

先创建一个类,MyConfig类,在类上面添加注解@Configuration,代表这是一个配置类,也会被spring托管,因为它本来就是一个@Component,等价于之前的applicationContext.xml

@ComponentScan(“com.kuang”)等价于之前的 <context:component-scan base-package=“com.kuang”/>

bean可能有多个,使用@Import(Config2.class)导入到一个配置类中使用

@Configuration  //代表这是一个配置类
@ComponentScan("com.kuang")
@Import(Config2.class)
public class MyConfig {
   
  @Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
    public UserService getUserService() {
        return new UserServiceImpl();
    }
}

三、动态代理

动态代理它可以直接给某一个目标对象生成一个代理对象,而不需要代理类存在。动态代理与静态代理原理是一样的,只是它没有具体的代理类,直接在程序运行时动态生成了一个代理对象。

动态代理分为两大类:

  • 基于接口的动态代理----JDK动态代理
  • 基于类的动态代理–cglib

主要使用JDK原生的动态代理,里面主要有两个类:

  • Proxy.newProxyInstance():产生代理接口的实例。

  • ClassLoader:类加载器。即被代理的接口的类加载器。

  • Class[] interface:代理类实现的接口(房东租房那个接口)

  • InvocationHandler:将要在代理中实现的功能写在该对象中

  • InvocationHandler中的invoke方法:调用代理类的任何方法,此方法都会执行

  • Object proxy:代理对象自身的引用。

  • Method method:当前被调用的方法。

  • Object[] args:当前被调用方法用到的参数

代码实现:

Rent (租房)即代理实现的接口

public interface Rent {
  public void rent();
}

Host (房东)即真实角色

//真实角色: 房东
public class Host implements Rent{
  public void rent() {
    System.out.println("房东要出租房子");
 }
}

ProxyInvocationHandler 即处理生成代理和调用方法

//动态代理类
public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;

    //注入
    public void setTarget(Object target) {
        this.target = target;
    }

    //生成动态代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(
                this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
    }

    //处理动态代理是实例,并返回一个结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(target, args);
        return result;
    }
}

Client:租客

//租客
public class Client {
  public static void main(String[] args) {
    //真实角色
    Host host = new Host();
    //代理实例的调用处理程序
    ProxyInvocationHandler pih = new ProxyInvocationHandler();
    pih.setRent(host); //将真实角色放置进去!
    Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
    proxy.rent();
 }
}

//结果输出:房东要出租房子

四、AOP

AOP是面向切面编程, 例如转账功能,在转账代码的前后需要一些非业务方面的处理 记录日志,这些代码就可以使用AOP将其切入到转账代码的前后, AOP的优点就是降低代码之间的耦合,提高代码的复用性。 (切入点、切面、通知)

代码实现:

使用自定义类的方式来实现AOP,开发中建议使用

环境准备:新建一个UserService接口,里面定义增删改查四个方法,创建它的实现类实现它的方法UserServiceImpl,

重点】使用AOP织入,需要导入一个依赖包!

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

DiyPointcut新建自定义切面类

//自定义类实现aop的方式
public class DiyPointcut {
    public void before(){
        System.out.println("------方法执行前----------");
    }
    public void after(){
        System.out.println("------方法执行后----------");
    }
}

applicationContext.xml,注意要有aop的头约束

<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"
       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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!--注册bean-->
    <bean id="userService" class="com.kuang.UserserviceImpl"/>
    
    <bean id="diy" class="com.kuang.aop2.DiyPointcut"/>
    <aop:config>
       <!--自定义切面,ref要引用类-->
        <aop:aspect ref="diy">
            <!--切入点-->
        <aop:pointcut id="diyPonitcut"expression="execution(*com.kuang.UserserviceImpl.*(..))"/>
        <!--通知-->
            <aop:before method="before" pointcut-ref="diyPonitcut"/>
            <aop:after method="after" pointcut-ref="diyPonitcut"/>
        </aop:aspect>
    </aop:config>
</beans>

五、spring的事务管理

事务的四个特性ACID原则(原子性,一致性,隔离性,持久性)

业务的增删改都需要事务,事务处理都在service层

1.要添加aop织入的包

<!--aop织入-->
    <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

2.spring-service.xml

<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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">


    <!-- 扫描service相关的bean -->
    <context:component-scan base-package="com.kuang.service" />
 
    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入数据库连接池 -->
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

<!--配置aop织入事务-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.kuang.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
</beans>

使用注解配置事务

此时只需要在配置文件中添加下面内容:

  <!-- 事务管理器 -->
<bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 数据源 -->
    <property name="dataSource" ref="dataSource" />
</bean>

<!--开启注解事务驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>

然后使用@Transactional 注解即可,该注解可以用于类上,也可以用于方法上,需要注意的是,@Transactional 若用在方法上,只能用于 public 方法上。对于其他非 public方法,如果加上了注解@Transactional,虽然 Spring 不会报错,但不会将指定事务织入到该方法中。因为 Spring 会忽略掉所有非 public 方法上的@Transaction 注解。

添加在类名上:

@Transactional
public class UserServiceImpl implements UserService {}

用在方法上,表示当抛出空指针异常时会进行回滚:

 @Transactional(propagation = Propagation.REQUIRED,rollbackFor = NullPointerException.class)
public void addUser(User user) throws Exception {
    userDao.addUser(user);
}

如果配置了事务,测试时获取bean时,返回的对象一定是接口

原因:

对于Spring AOP 采用两种代理方法,一种是常规JDK,一种是CGLIB,代理对象实现了至少一个接口,默认使用JDK动态创建代理对象,当代理对象没有实现任何接口时,就会使用CGLIB方法 ,就会报错

添加在类名上:

@Test
public void test22() {

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    //接口
    UserService userService = (UserService) applicationContext.getBean("userServiceImpl");
    List<User> users = userService.selectUser();
    for (User user : users) {
        System.out.println(user);
    }
}

六、 @Autowired@Resource 的区别

两个都是用作bean的注入

共同点

@Resource和@Autowired都可以作为注入属性的修饰 ,在接口仅有单一实现类的时候,两个的注解修饰效果是相同的。

不同点

  • @Resource是Java自己的注解 ,@Autowired是 spring中的注解
  • @Resource有两个属性是比较重要的,分是name和type , name属性解析为bean的名字 , 而type属性则解析为bean的类型 。如果都不指定,这是通过反射机制默认是按照 byName自动注入策略
  • @Autowired 是spring2.5版本引入的 , Autowired只根据type进行注入,不会去匹配name。 如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier (就是一个接口有两个实现类无法辨别)

例子:

创建一个UserDao接口

public interface UserDao {

    public void getUser();

}

UserDao接口,有两个实现类

创建UserDaoImplMysql类实现UserDao,并在类上添加注解注入到spirng中

@Repository
public class UserDaoImplMysql implements UserDao {

    public void getUser() {
        System.out.println("MySQL获取用户数据!");
    }
}

UserDaoImplOracle

@Repository
public class UserDaoImplOracle implements UserDao {

    public void getUser() {

        System.out.println("Oracle获取用户数据!");
    }
}

创建UserService接口

public interface UserService {

    public void getUser();
}

创建UserServiceImpl类实现UserService

@Service
public class UserServiceImpl implements UserService {

	//使用@Resource
    //@Resource(name = "userDaoImplOracle") //按bena的名字
    @Resource(type = UserDaoImplOracle.class) //按类型
    
    //使用@Autowired
    @Autowired
    @Qualifier("userDaoImplOracle") //要指定是哪个bean
    private UserDao userDao;

    public void getUser() {
        userDao.getUser();
    }
}

测试类:

@Test
public void test001(){

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userServiceImpl");

        userService.getUser();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值