这是个系列教程,看完这个,你对JavaEE注解,包括spring、hibernate,RESTFul web service ,JAXB, 以及junit注解将会有一个全面的了解。
英文原版网址在这里 我们不光是spring网站的搬运工@农夫山泉水,实际上,翻译过程中我保证准确同时,加入了自己的理解。
** Spring Annotations 列表: **
@Service
import org.springframework.stereotype.Service;
@Repository
import org.springframework.stereotype.Repository;
@Component
import org.springframework.stereotype.Component;
@Autowired
import org.springframework.beans.factory.annotation.Autowired;
@Transactional
import org.springframework.transaction.annotation.Transactional;
@Scope
import org.springframework.context.annotation.Scope;
以及
@Controller
import org.springframework.stereotype.Controller;
@RequestMapping
import org.springframework.web.bind.annotation.RequestMapping;
@PathVariable
import org.springframework.web.bind.annotation.PathVariable;
@RequestParam
import org.springframework.web.bind.annotation.RequestParam;
@ModelAttribute
import org.springframework.web.bind.annotation.ModelAttribute;
@SessionAttributes
import org.springframework.web.bind.annotation.SessionAttributes;
Spring Security Annotations
@PreAuthorize
import org.springframework.security.access.prepost.PreAuthorize;
首先看一下一个典型的Java web项目结构:
part1. Spring Annotations
@Service 用在所有业务逻辑代码类中,对应图中service package下的类
@Service
public class UserServiceImpl implements UserService{
}
@Repository用在领域类,对应三层的DAO层(数据库操作类),上图 的domain package:
@Repository
public interface UserRepo extends JpaRepository<User,Integer> {
User findByName(String name);
}
@Component用在其它组件(无法分类的,如工具类)
实际上,Component注解和其它注解有如下关系:
@Autowired
自动织入其他bean到你的类中(Ioc,Spring精髓)
@Service
public class CompanyServiceImpl implements CompanyService {
@Autowired
private CompanyDAO companyDAO;
...
}
@Transactional
开启事务
@Service
public class CompanyServiceImpl implements CompanyService {
@Autowired
private CompanyDAO companyDAO;
//开启事务后,当此方法出错,数据将会回滚
//比如,连续添加10条数据,第7条出错,则最后一条都不会添加,若
//不加Trsanctional,则会添加6条
@Transactional
public Company saveName(Company comp) {
Company company = companyDAO.save(comp);
return company;
}
}
@Scope:
这个首先看一下spring中scope定义:
** scope概论**
spring中scope是一个非常关键的概念,简单说就是对象在spring容器(IOC容器)中的生命周期,也可以理解为对象在spring容器中的创建方式。
scope历史及分类
目前,scope的取值有5种取值:
在Spring 2.0之前,有singleton和prototype两种;
在Spring 2.0之后,为支持web应用的ApplicationContext,增强另外三种:request,session和global session类型,它们只实用于 web程序,通常是和XmlWebApplicationContext共同使用。
单个scope详解
- singleton (单一实例)
此取值时表明容器中创建时只存在一个实例,所有引用此bean都是单一实例。如同每个国家都有一个总统,国家的所有人共用此总统,而这个国家就是一个spring容器,总统就是spring创建的类的bean,国家中的人就是其它调用者,总统是一个表明其在spring中的scope为singleton,也就是单例模型。
此外,singleton类型的bean定义从容器启动到第一次被请求而实例化开始,只要容器不销毁或退出,该类型的bean的单一实例就会一直存活,典型单例模式,如同servlet在web容器中的生命周期。
2)prototype
spring容器在进行输出 prototype的bean 对象时,会每次都重新生成一个新的对象给请求方,虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不在拥有当前对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每次返回请求方该对象的一个新的实例之后,就由这个对象“自生自灭”,最典型的体现就是spring与struts2进行整合时,要把action的scope改为prototype。
如同分苹果,将苹果的bean的scope属性声明为prototype,在每个人领取苹果的时候,我们都是发一个新的苹果给他,发完之后,别人爱怎么吃就怎么吃,爱什么时候吃什么时候吃,但是注意吃完要把苹果核扔到垃圾箱!对于那些不能共享使用的对象类型,应该将其定义的scope设为prototype。
3)request
再次说明 request,session和global session类型只实用于 web程序,通常是和XmlWebApplicationContext共同使用。
<bean id ="requestPrecessor" class="...RequestPrecessor" scope="request" />
Spring容器,即XmlWebApplicationContext 会为每个HTTP请求创建一个全新的RequestPrecessor对象,当请求结束后,该对象的生命周期即告结束, **如同java web中request的生命周期 **。 当同时有100个HTTP请求进来的时候,容器会分别针对这10个请求创建10个全新的RequestPrecessor实例,且他们相互之间互不干扰, 简单来讲, request可以看做prototype的一种特例 ,除了场景更加具体之外,语意上差不多。
4)session
对于web应用来说,放到session中最普遍的就是用户的登录信息,对于这种放到session中的信息,我们可以使用如下形式的制定scope为session:
<bean id ="userPreferences" class="...UserPreferences" scope="session" />
Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,比request scope的bean会存活更长的时间,其他的方面没区别, 如果java web中session的生命周期 。
5)global session
<bean id ="userPreferences" class="...UserPreferences" scope="globalsession" />
global session只有应用在基于porlet的web应用程序中才有意义,它映射到porlet的global范围的session,如果普通的servlet的web 应用中使用了这个scope,容器会把它作为普通的session的scope对待。
@Scope声明现在就能看懂了吧
@Component
@Scope("request")
public class ContactResource {
...
}
part 2 . Spring MVC Annotations
@Controller, @RequestMapping,@PathVariable,@RequestParam这几个太常用了,来不及解释了,补充一点就是还可以使用 @RequestHeader获得header信息
@ModelAttribute是java中的数据绑定,用于将表单对应项绑定到模型
@Controller
@RequestMapping("/company")
public class CompanyController {
@Autowired
private CompanyService companyService;
@RequestMapping("/add")
public String saveNewCompany(@ModelAttribute Company company) {
companyService.add(company);
return "redirect:" + company.getName();
}
...
}
@SessionAttributes就是保存session,定义在一个Controller类上
@RestController
@RequestMapping("/user")
@SessionAttributes("currUser")
public class UserController {
@Autowired
private UserRepo userRepo;
@Transactional
@RequestMapping("/save")
public User save(User user){
User newUser = userRepo.save(user);
return newUser;
}
}
SessionAttributes 可以和ModelAttribute结合使用, 我们可以在需要访问 Session 属性的 controller 上加上 @SessionAttributes,然后在 action 需要的 User 参数上加上 @ModelAttribute,并保证两者的属性名称一致。
@Controller
@SessionAttributes("currentUser")
public class GreetingController{
@RequestMapping
public void hello (@ModelAttribute("currentUser") User user){
//user.sayHello()
}
}
一个综合以上的实例:
@Controller
@RequestMapping("/owners/{ownerId}/pets/{petId}/edit")
@SessionAttributes("pet")
public class EditPetForm {
@ModelAttribute("types")
public Collection<PetType> populatePetTypes() {
return this.clinic.getPetTypes();
}
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet,
BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "petForm";
}else {
this.clinic.storePet(pet);
status.setComplete();
return "redirect:owner.do?ownerId="
+ pet.getOwner().getId();
}
}
}
@PreAuthorize:预检查
@Transactional
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void removeContact(Integer id) {
contactDAO.removeContact(id);
}