Spring框架的四大原则:
- 使用POJO进行轻量级和最小侵入式的开发。
- 通过依赖注入和基于接口编程实现松耦合。
- 通过AOP和默认习惯进行声明式编程。
- 使用AOP和模板减少模式化代码。
依赖注入
控制反转(Inversion of Control-IOC)和依赖注入(dependency injection-DI)
控制反转是通过依赖注入实现的。所谓的依赖注入指的是容器负责创建对象和维护对象间的依赖关系,而不是通过对象本身负责自己的创建和解决自己的依赖。
Spring IOC容器(ApplicationContext)负责创建Bean,并通过容器将功能类Bean注入到你需要的Bean中。
Spring提供使用XML,注解,Java配置,groovy配置实现Bean的创建和注入。
声明Bean的注解:
@Component 没有明确的角色
@Service 在业务逻辑层(Service层)使用
@Respository 在数据访问层(dao层)使用
@Controller 在展现层使用
注入Beande 的注解,一般情况下通用:
@Autowired Spring提供的注解
@Inject JSR-330提供的注解
@Resource JSR-250提供的注解
关于注解的示例:
引入spring的基础包,当中有对注解的支持。要支持inject需要额外引包
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xhf</groupId>
<artifactId>SpringSample1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringSample1</name>
<properties>
<java.version>1.7</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<!-- inject依赖的jar包 -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
定义一个方法,后面通过注入的方式实例化这个方法
package com.xhf.sample1;
import org.springframework.stereotype.Service;
@Service
public class FunctionService {
public String sayHello(String word) {
return "Hello " + word + "! ";
}
}
这里通过注入实例化Bean,并且进行使用
package com.xhf.sample1;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UseFunctionService {
//spring提供的注入注解
@Autowired
FunctionService functionService1;
//使用这个注解需要引入javax.inject的jar包,maven依赖可已看pom文件
@Inject
FunctionService functionService2;
@Resource
FunctionService functionService3;
public String sayHello(String word) {
return functionService1.sayHello(word) + functionService2.sayHello(word) + functionService3.sayHello(word);
}
}
定义一个配置类,确定扫描组件的范围
package com.xhf.sample1;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration //这表示这是一个配置类
@ComponentScan("com.xhf.sample1") //从这个包里扫描组件
public class DiConfig {
}
执行方法,看看注入是否成功
package com.xhf.sample1;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DiConfig.class);
UseFunctionService useFunctionService = context.getBean(UseFunctionService.class);
String result = useFunctionService.sayHello("world");
System.out.println(result);
context.close();
}
}
输出:
Hello world! Hello world! Hello world!
AOP
面向切面编程相对于OOP(面向对象编程)能够使代码的耦合度降低。Spring支持AspectJ的注解切面编程。
- 使用@Aspect声明是一个切面。
- 使用@After @Before @Around 定义建言 advice,可直接将拦截规则(切点)作为参数。
- 其中@After @Before @Around 参数的拦截规则为切点(PointCut),为了使切点复用,可使用@PointCut 专门定义拦截规则,然后在@After @Before @Around 的参数中调用。
- 其中符合条件的每一个被拦截处为连接点。
这里给出一个简单的示例
添加aspectJ的依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xhf</groupId>
<artifactId>SpringSample1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringSample1</name>
<properties>
<java.version>1.7</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- 添加spring aop支持以及AspectJ依赖 -->
<!-- spring aop支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
<!-- aspectJ支持 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
定义一个注解,可以通过注解拦截指定的方法
//此处定义一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
String name();
}
定义几个被拦截的方法
通过注解拦截的方法
@Service
public class DemoAnnotationService {
//在方法上加一个注解,拦截的时候可根据方法上的注解进行拦截
@Action(name="注解式拦截的add操作")
public void add() {System.out.println("add 方法执行");};
}
正常的方法,后面可根据方法限定名等定义拦截规则进行拦截
@Service
public class DemoMethodService {
public void add() {System.out.println("add 方法执行");}
}
要被around前后都拦截的方法
@Service
public class AroundDemoMethodService {
public void add() {System.out.println("around add 方法执行");}
}
定义切面,这里定义了各种拦截的规则,以及拦截后在切面上执行一些程序
//Aspect声明这是一个切面
@Aspect
//Component让此切面成为spring管理容器的Bean
@Component
public class LogAspectJ {
//通过pointcut可以声明一个切点,参数为拦截规则,下面规则表示所有被Action注解的方法会被拦截
@Pointcut("@annotation(com.xhf.sample2.Action)")
public void annotationPointCut(){};
//声明一个一个建言Advice,使用Pointcut定义的切点。在执行完那个被拦截的方法之后会执行这个建言中的程序。
@After("annotationPointCut()")
public void after(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
Action action = method.getAnnotation(Action.class);
System.out.println("注解式拦截 " + action.name());
}
//这里直接使用execution函数定义拦截规则。
@Before("execution(* com.xhf.sample2.DemoMethodService.*(..))")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("方法规则式拦截 " + method.getName());
}
//使用around进行拦截可以在方法执行前后执行一些程序
@Around("execution(* com.xhf.sample2.AroundDemoMethodService.*(..))")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("around执行前");
try {
//被around拦截的方法必须执行这句程序才会执行被拦截的方法
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("around执行后");
}
}
定义配置类,开启aspectJ的支持
//表示这是一个配置文件
@Configuration
//spring扫描的包,在这范围内处理各类注解
@ComponentScan("com.xhf.sample2")
//开启spring对aspectJ代理的支持
@EnableAspectJAutoProxy
public class AopConfig {
}
最后是执行一下各个方法,看看拦截的效果
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(AopConfig.class);
DemoAnnotationService demoAnnotationService
= context.getBean(DemoAnnotationService.class);
DemoMethodService demoMethodService
= context.getBean(DemoMethodService.class);
AroundDemoMethodService aroundDemoMethodService
= context.getBean(AroundDemoMethodService.class);
demoAnnotationService.add();
demoMethodService.add();
aroundDemoMethodService.add();
context.close();
}
}
输出:
add 方法执行
注解式拦截 注解式拦截的add操作
方法规则式拦截 add
add 方法执行
around执行前
around add 方法执行
around执行后