注解注入(重点)
(1)导入AOP的Jar包。因为注解的后台实现用到了AOP编程。
使用注解所需要的包: org.springframework:spring-aop:5.2.2.RELEASE
(2)需要更换配置文件头,即添加相应的约束。
(3)需要在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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="spring"></context:component-scan>
</beans>
定义Bean@Component
- 需要在类上使用注解@Component,该注解的value属性用于指定该bean的id值。
//放在类上,等价于注册了<bean id="user" class="cn.pinked.pojo.User"/>
@Component
public class User {
public String name;
}
基本类型属性注入@Value
- 需要在属性上使用注解@Value,该注解的value属性用于指定要注入的值。
- 使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。
//相当于<property name="name" value="大头儿子"/>
@Value("大头儿子")
public void setName(String name) {
this.name = name;
}
衍生的注解
另外,Spring还提供了3个功能基本和@Component等效的注解:
在web开发中,会按照mvc三层架构分层
@Repository 用于对DAO实现类进行注解
@Service 用于对Service实现类进行注解
@Controller 用于对Controller实现类进行注解
之所以创建这三个功能与@Component等效的注解,是为了以后对其进行功能上的扩展,使它们不再等效。
按类型注入域属性@Autowired,@Autowired是spring的注解
- 需要在域属性上使用注解@Autowired,该注解默认使用按类型自动装配Bean的方式。
- 使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。
@component( "mySchool")
public class School{
@Value("school")
private String name;
}
@component ( "myStudent")
public class Student{
@value("张三")
private String name;
@value("21")
private int age;
@Autowired
private School school;
}
Bean的作用域@Scope
- 需要在类上使用注解@Scope,其value属性用于指定作用域。默认为singleton。
域属性注解@Resource,也就是说@Resource是java自带的注解
- @Resource注解既可以按名称匹配Bean,也可以按类型匹配Bean。使用该注解,要求JDK必须是6及以上版本。
(1)按类型注入域属性
@Resource注解若不带任何参数,则会按照类型进行Bean的匹配注入。
(2)按名称注入域属性
@Resource注解指定其name属性,则name的值即为按照名称进行匹配的Bean的id。
小结
- xml与注解
xml更加万能,适用于任何场合,维护方便
注解不是自己的类使用不了,维护相对复杂- 最佳实践:
xml负责管理bean
注解负责属性的注入
使用Java的方式配置Spring
JavaConfig,是在Spring 3.0开始从一个独立的项目并入到Spring中的。JavaConfig可以看成一个用于完成Bean装配的配置文件,只不过是程序员使用Java自己编写的。
实体类:
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("大头儿子")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置文件:
//这个也会被Spring容器托管,注册到容器中,因为它自身就是一个@Component,
// @Configuration代表这是一个配置类,就和我们之前看的beans.xml一样
@Configuration
@Import(AppConfig2.class)
public class AppConfig {
//注册一个bean,就相当于我们之前写的一个bean标签
//这个方法的名字,就相当于bean标签中的ID属性
//这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User getUser() {
return new User();//就是返回要注入到bean的对象
}
}
测试:
@Test
public void user() {
//如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载!
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
User getUser = (User) context.getBean("getUser");
System.out.println(getUser.toString());
}
AOP
简介
AOP意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP 术语
在我们开始使用 AOP 工作之前,让我们熟悉一下 AOP 概念和术语。这些术语并不特定于 Spring,而是与 AOP 有关的。
项 | 描述 |
---|---|
横切关注点 | 跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等… |
切面(ASPECT) | 横切关注点被模块化的特殊对象。即,它是一个类。 |
通知(Advice) | 切面必须要完成的工作。即,它是类中的一个方法。 |
目标(Target) | 被通知对象。 |
代理(Proxy) | 向目标对象应用通知之后创建的对象。 |
切入点(PointCut) | 切面通知执行的“地点“的定义 |
连接点(JointPoint) | 与切入点匹配的执行点 |
通知的类型
Spring 方面可以使用下面提到的五种通知工作:
通知 | 描述 |
---|---|
前置通知 | 在一个方法执行之前,执行通知。 |
后置通知 | 在一个方法执行之后,不考虑其结果,执行通知。 |
返回后通知 | 在一个方法执行之后,只有在方法成功完成时,才能执行通知。 |
抛出异常后通知 | 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。 |
环绕通知 | 在建议方法调用之前和之后,执行通知。 |
使用Spring实现AOP
导入依赖包
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
使用自定义类实现AOP
public class Logging {
public void before(){
System.out.println("=====方法执行前=====");
}
public void after(){
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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean name="userService" class="spring.service.impl.UserServiceImpl" ></bean>
<bean name="lg" class="spring.aspectj.Logging" ></bean>
<aop:config>
<aop:aspect ref="lg">
<aop:pointcut id="pointcut" expression="execution(* spring.service.impl.*.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
使用注解实现AOP
@Aspect
public class PointCut {
@Pointcut("execution(public * spring.service.impl.UserServiceImpl.*())")
public void a() {
}
@Before("a()")
public void before(){
System.out.println("=====方法执行前=====");
}
@After("a()")
public void after(){
System.out.println("=====方法执行后=====");
}
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="spring"></context:component-scan>
<aop:aspectj-autoproxy/>
</beans>