spring相关

tech2023-08-19  96

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(); }
最新回复(0)