Spring框架入门
Spring中的IOC思想
Spring中的IOC,英文全称为Inversion of control,意思为控制反转。什么意思呢?我们可以具体说说,在一开始接触Java的时候,我们都是使用new来手动创建一个对象的,但是IOC思想就是让Spring容器帮我们创建好对象,我们直接使用即可,在代码里面很直观的体现就是我们很少看到new 的存在(当然我们配置文件的时候还是需要的)。
一个小小的demo:
首先是xml配置文件(写的有点杂,核心的就是开头的几行代码,后面的是一些想关的p标签、c标签以及一些方法的应用)
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsdspring-context.xsd">
<!-- 无参构造-->
<bean id="user" class="com.Tom.pojo.User" name="user3,user4">
<property name="name" value="Spring"/>
</bean>
<!-- 别名-->
<alias name="user" alias="user2"/>
<!-- 使用p标签的无参构造 -->
<!-- <bean id="user" class="com.ztLin.pojo.User" p:name="Tom"/> -->
<!-- 有参构造的三种方法-->
<!-- <bean id="user" class="com.Tom.pojo.User">-->
<!-- <constructor-arg index="0" value="123"/>-->
<!-- </bean>-->
<!-- <bean id="user" class="com.Tom.pojo.User">-->
<!-- <constructor-arg type="java.lang.String" value="123"/>-->
<!-- </bean>-->
<!-- <bean id="user" class="com.Tom.pojo.User">-->
<!-- <constructor-arg ref=""/>-->
<!-- </bean>-->
<!-- 使用c标签的有参构造-->
<!-- <bean id="user" class="com.Tom.pojo.User" c:_0="Tom"/> -->
</beans>
接下来是Java的测试类
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user");
System.out.println(user.toString());
}
}
我们在使用user的时候就最直接从Spring容器中取出这个user对象就可以了,看起来好像变化不大,但其实使得对象在容器中创建,修改代码只需要修改配置文件即可。
Spring中的AOP思想
Spring中的AOP,英文全称为Aspect-oriented Programming,意思为面向切面编程。那么切面又是一个什么概念呢?在这里先引入一个纵向编程的概念,个人理解的纵向编程就是在从上往下,逐层递进编程,比如做一个JavaWeb项目,首先我们需要编写实体类,DAO层,Service层,Servlet层…切面就可以理解为这一个一个的层,面向切面编程就是在完成纵向编程之后,比如我们需要增加一个日志Log功能,那么我们在不改变Service这一层代码的情况下增加一个可以复用的功能。
Spring中的AOP是基于动态代理实现的,而动态代理又是通过反射实现的。但是呢,Spring是Java程序员的春天嘛,它作为一个简单易用的容器,当然也就帮我们屏蔽掉一些细节啦。
一共有三种方式实现AOP,下面可以看看简略版本!
使用注解@Aspect
我们可以使用xml进行配置,比如说要在执行一个方法的前后增加两个功能,当然也需要实现的Java需要的操作。(第一句开启springAOP注解一定不要忘啦!)
<aop:aspectj-autoproxy/>
<bean id="annotationPointCut" class="com.Tom.diy.AnnotationPointCut"/>
下面是Java的代码:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointCut {
@Before("execution(* com.Tom.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前!");
}
@After("execution(* com.Tom.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后!");
}
@Around("execution(* com.Tom.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Object o = jp.proceed();
System.out.println("环绕后");
}
}
使用diy的方法加上xml配置
在标签中配置before标签和after标签
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="point" expression="execution(* com.Tom.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
然后就是我们的diy类
public class diy {
public void before(){
System.out.println("这是方法执行前!");
}
public void after(){
System.out.println("这是方式执行后!");
}
}
使用继承接口和xml配置
在xml配置文件中,我们注册并使用before和after两个bean
<bean id="log" class="com.Tom.log.Log"/>
<bean id="afterLog" class="com.Tom.log.AfterLog"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.Tom.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
然后再com.Tom.Log中我们创建如下两个类
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("执行了"+method.getName()+",执行的结果为:"+o);
}
}
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"被执行了!");
}
}
上述的方法使得我们不必要每次都去修改每一层(切面)的代码,交给AOP来代理,配置完可以在不改变原有层代码的基础上增加重复的功能。
Spring中的一些常用注解
@Autowired
@Autowired对应的是自动装配的功能,自动装配就是说比如在applicationContext中我们注册了三个Bean,一个human,一个为cat,一个为dog,而human中有cat、dog这个属性,如果你在human中cat、dog属性的上方打上@Autowired这个注解,那么在Spring中就不必在human的配置中声明他的dog和cat是对应哪个,但如果同时有多个dog和cat,则必须通过配合@Qualifier(value=“XXX”),cat和dog在bean中绑定的名称实现自动装配。在applicationContext中进行如下配置
<bean id="cat" class="com.Tom.pojo.Cat"/>
<bean id="dog" class="com.Tom.pojo.Dog"/>
<bean id="human" class="com.Tom.pojo.Human" p:name="XXX"/>
在Human类中,进行如下配置即可
public class Human {
@Autowired
@Qualifier(value="cat")//这里可以省略,也可以在set方法上自动装配
private Cat cat;
@Autowired
private Dog dog;
}
@Nullable
@Nullable是允许当前属性的值为空。
@Nullable
public String name ;
@Resource
@Resource注解和@Autowired这个注解的作用有些相似,都是自动装配,但是它是先按照名称来装配,与@Autowired不同(先类别,后名称),不是spring的原生注解,但由于与@Autowired相似,故放在一起。
@Resource(name="cat")
private Cat cat;
这里有一个小坑,annotation需要导入的maven依赖是
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.1</version>
</dependency>
而不是
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
@Component
@Component注解使用后会被加载到IOC容器中,
@Component
public class Human{}
与bean的作用相似。相当于下面的代码
<bean id="human" class="com.Tom.pojo.Human" p:name="XXX"/>
但是一定要记得加上扫描的包
<context:component-scan base-package="com.Tom"/>
@Value
@Value可以使用在属性或者对应属性的set方法上,实现值的设置。
@Value("Tom")
private String name;
或者
@Value("Tom")
public void setName(String name) {
this.name = name;
}
@Controller
@Controller注解用来标注控制层,与Component的一样都会被加载到IOC容器。(注入服务)
@Controller
public class UserController {}
@Service
@Service注解标注服务层,主要用来进行业务的逻辑处理,与Component的一样都会被加载到IOC容器。(注入DAO)
@Service
public class UserService {}
@Repository
@Repository注解标记数据访问层,与Component的一样都会被加载到IOC容器。(实现DAO访问)
@Repository
public class UserDao {}
@Scope
@Scope注解为指定作用域,可以指定为singleton单例模式、prototype原型模式,一般来说,在单线程使用singleton节约资源,多线程使用prototype实现高并发。(默认为singleton)
@Component
@Scope("singleton")
public class User {
@Value("注解")
public String name ;
}
下面总结一下使用Spring过程中遇到的坑
导包出错,比如使用注解开发
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.1</version>
</dependency>
这个才是正确的的annotation包(所以说该到maven官网查咱就别省了这一步)